diff --git a/Application/functions.js b/Application/functions.js new file mode 100644 index 00000000..04cda7fa --- /dev/null +++ b/Application/functions.js @@ -0,0 +1,35 @@ +/** + * construct an application object so that we can use + * skins for non-active applications too + * @arg name + */ +function constructor(name) { + this.name = name; +} + + +/** + * overrides the internal href-function, as + * helma.framework.core.Application.getNodeHref(Object,String) + * isn't able to compute correct urls for non-node objects. + * @arg action of application + */ +function href(action) { + var url = getProperty("baseURI"); + url = (url==null || url=="null") ? "" : url; + url += this.name + "/" + ( (action!=null && action!="") ? action : "main" ); + return url; +} + + +/** + * return true/false to determine if application is running + */ +function isActive() { + if ( root.getApplication(this.name)==null ) + return false; + else + return true; +} + + diff --git a/Application/head.skin b/Application/head.skin new file mode 100644 index 00000000..a52e6407 --- /dev/null +++ b/Application/head.skin @@ -0,0 +1,10 @@ +

AppManager <% this.title %> +<% this.description prefix="
" %> +
+ -> + /main">AppDoc | + public | + ?app=<% this.title %>&action=flush">flush | + ?app=<% this.title %>&action=restart">restart | + ?app=<% this.title %>&action=stop">stop +

diff --git a/Application/macros.js b/Application/macros.js new file mode 100644 index 00000000..9eec3fe5 --- /dev/null +++ b/Application/macros.js @@ -0,0 +1,172 @@ +/** + * macro rendering a skin + * @param name name of skin + */ +function skin_macro(par) { + if ( par && par.name ) { + this.renderSkin(par.name); + } +} + + +/** + * macro-wrapper for href-function + * @param action name of action to call on this prototype, default main + */ +function href_macro(par) { + return this.href( (par&&par.action)?par.action:"main" ); +} + + +/** + * Macro returning the URL of an application. + * using absoluteURI if set in app.properties, otherwise we go for the href calculated by + * the application (which is using baseURI if set) + */ +function url_macro() { + var str = this.getProperty("absoluteuri"); + if ( str!=null && str!="" ) { + return str; + } else { + return this.getRootHref(); + } +} + + +/** + * Macro returning the title of an application + */ +function title_macro() { + var title = this.name; + return(title); +} + + +/** + * Macro rendering a description of an application from a + * file called description.txt or doc.html located in the + * app's root. Limits description to 200 chars. + * @param Object Macro parameter object + */ +function description_macro(param) { + var str = ""; + var appHome = this.getAppDir(); + var f = new File(this.getAppDir().toString(), "description.txt"); + if (!f.exists()) + f = new File(this.getAppDir().toString(), "doc.html"); + if (f.exists()) { + str = f.readAll(); + if (str.length > 200) + str = str.substring(0, 200) + "..."; + } + return(str); +} + + +/** + * Macro returning the server's uptime nicely formatted + */ +function uptime_macro() { + return formatAge( (java.lang.System.currentTimeMillis()-this.starttime) / 1000 ); +} + + +/** + * Macro returning the number of active sessions. + * parameter used by global.formatCount + * @see global.formatCount + */ +function countSessions_macro(par) { + if ( this.isActive()==true ) + return this.sessions.size() + formatCount(this.sessions.size(),par); + else + return 0; +} + + +/** + * Macro returning the number of logged-in users or the list + * of logged-in users if http-parameter showusers is set to true. + * Makes use of this.countUsers_macro and this.listUsers_macro + * @see application.countUsers_macro + * @see application.listUsers_macro + */ +function users_macro(par) { + if ( req.data.showusers=="true" ) { + this.listUsers_macro(par); + } else { + this.countUsers_macro(par); + } +} + + +/** + * Macro returning the number of logged-in users if application + * is active + * parameter used by global.formatCount + * @see global.formatCount + */ +function countUsers_macro(par) { + if ( this.isActive()==true ) + return this.activeUsers.size() + formatCount(this.activeUsers.size(),par); + else + return 0; +} + + +/** + * Macro rendering the list of logged-in users if application is active + * @param separator html-code written between elements + */ +function listUsers_macro(par) { + var separator = (par && par.separator) ? par.separator : ", "; + if ( this.activeUsers.size()==0 ) + return ""; + var e = this.activeUsers.keys(); + while ( e.hasMoreElements() ) { + res.write ( e.nextElement() ); + if ( e.hasMoreElements() ) { + res.write ( separator ); + } + } +} + + +/** + * Macro returning the number of active evaluators (=threads) + */ +function countActiveEvaluators_macro() { + return this.countActiveEvaluators(); +} + + +/** + * Macro returning the number of free evaluators (=threads) + */ +function countFreeEvaluators_macro() { + return this.countFreeEvaluators(); +} + + +/** + * Macro formatting the 5min average of requests. + */ +function getRequestAvg_macro(par) { + if ( app.requestStat==null || app.requestStat.get(this.name)==null ) + return 0; + if ( this.isActive() ) { + var obj = app.requestStat.get(this.name); + return obj.last5Min + formatCount(obj.last5Min,par); + } else { + return 0 + formatCount(0,par); + } +} + + +/** + * Macro formatting app.properties + */ +function properties_macro(par) { + formatProperties( this.getProperties(), par ); +} + diff --git a/Application/main.hac b/Application/main.hac new file mode 100644 index 00000000..40a43c35 --- /dev/null +++ b/Application/main.hac @@ -0,0 +1,10 @@ +/** + * renders AppManager + */ + +if ( checkAddress()==false ) return; +if ( checkAuth(this)==false ) return; + +res.skin="global"; +res.body = this.renderSkinAsString("main"); + diff --git a/Application/main.skin b/Application/main.skin new file mode 100644 index 00000000..0b05f12d --- /dev/null +++ b/Application/main.skin @@ -0,0 +1,42 @@ +<% this.skin name="head" %> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<% this.properties prefix="" %> +
application
active sessions: <% this.countSessions %>
?showusers=true">logged-in users: <% this.users %> 
active evaluators: <% this.countActiveEvaluators %>
free evaluators: <% this.countFreeEvaluators %>
5min-request-avg: <% this.getRequestAvg %>
uptime: <% this.uptime %>
app.properties
" separator=" " suffix="
+ diff --git a/Application/mrtg.hac b/Application/mrtg.hac new file mode 100644 index 00000000..fb324794 --- /dev/null +++ b/Application/mrtg.hac @@ -0,0 +1,23 @@ +/** + * prints session- and thread-stats for mrtg-tool + * doesn't check username or password, so that we don't have + * to write them cleartext in a mrtg-configfile + */ + +if ( checkAddress()==false ) return; + +if ( this.isActive()==false ) { + res.write ( "0\n0\n0\n0\n"); + return; +} + +if ( req.data.action=="sessions" ) { + res.write ( this.sessions.size() + "\n0\n0\n0\n" ); + return; +} + +if ( req.data.action=="threads" ) { + res.write ( this.countActiveEvaluators() + "\n" + this.countFreeEvaluators() + "\n0\n0\n"); + return; +} + diff --git a/Application/navig_active.skin b/Application/navig_active.skin new file mode 100644 index 00000000..afd05311 --- /dev/null +++ b/Application/navig_active.skin @@ -0,0 +1,15 @@ +
+ "><% this.title %>
+ <% this.countSessions singular=" Session" plural=" Sessions" %>, <% this.getRequestAvg singular=" Request" plural=" Requests" %>/5min +
+ +
+
diff --git a/Application/navig_disabled.skin b/Application/navig_disabled.skin new file mode 100644 index 00000000..c49223d1 --- /dev/null +++ b/Application/navig_disabled.skin @@ -0,0 +1,10 @@ +
+ + + + +
+ ?app=<% this.title %>&action=start">start +
+ <% this.title %> +
diff --git a/Application/redirectpublic.hac b/Application/redirectpublic.hac new file mode 100644 index 00000000..7ead5169 --- /dev/null +++ b/Application/redirectpublic.hac @@ -0,0 +1,10 @@ +/** + * performs a redirect to the public site + * (workaround, we can't access application object from docapplication for some reason) + * @see application.url_macro + */ + +if ( checkAddress()==false ) return; +if ( checkAuth(this)==false ) return; + +res.redirect ( this.url_macro() ); diff --git a/DocApplication/functions.js b/DocApplication/functions.js new file mode 100644 index 00000000..fbbd7872 --- /dev/null +++ b/DocApplication/functions.js @@ -0,0 +1,14 @@ +/** + * overrides the internal href-function, as + * helma.framework.core.Application.getNodeHref(Object,String) + * isn't able to compute correct urls for non-node objects. + * @arg action of application + */ +function href(action) { + var url = getProperty("baseURI"); + url = (url==null || url=="null") ? "" : url; + url += this.name + "/api/" + ( (action!=null && action!="") ? action : "main" ); + return url; +} + + diff --git a/DocApplication/head.skin b/DocApplication/head.skin new file mode 100644 index 00000000..1bd8e6a2 --- /dev/null +++ b/DocApplication/head.skin @@ -0,0 +1,8 @@ +

AppDoc <% this.name %> +
+ -> + AppManager | + ">public +

+ + diff --git a/DocApplication/index.skin b/DocApplication/index.skin new file mode 100644 index 00000000..51fc7746 --- /dev/null +++ b/DocApplication/index.skin @@ -0,0 +1,11 @@ + +

AppDoc <% this.name %>

+ + + + +<% this.index skin="indexList" %> +
+ +
+ diff --git a/DocApplication/macros.js b/DocApplication/macros.js new file mode 100644 index 00000000..a18e1142 --- /dev/null +++ b/DocApplication/macros.js @@ -0,0 +1,74 @@ +/** + * macro rendering a skin + * @param name name of skin + */ +function skin_macro(par) { + if ( par && par.name ) { + this.renderSkin(par.name); + } +} + + +/** + * macro-wrapper for href-function + * @param action name of action to call on this prototype, default main + */ +function href_macro(par) { + return this.href( (par&&par.action)?par.action:"main" ); +} + + +/** + * link to the "real" application object (ie not the DocApplication) + */ +function parentlink_macro(par) { + var url = getProperty("baseURI"); + url = (url==null || url=="null") ? "" : url; + url += this.name + "/"; + url += (par&&par.action)?par.action:"main"; + return url; +} + + +/** + * list all prototypes of this application + * @param skin name of skin to render on prototype + */ +function prototypes_macro(par) { + var skin = (par && par.skin&&par.skin!="")?par.skin:"appList"; + var arr = this.listPrototypes(); + for ( var i=0; i + + + + + + <% this.prototypes skin="appList" %> +
Prototypes
+ +
+ diff --git a/DocApplication/navig.skin b/DocApplication/navig.skin new file mode 100644 index 00000000..f639e52a --- /dev/null +++ b/DocApplication/navig.skin @@ -0,0 +1,14 @@ +<% this.name %> + +
+
  • ?action=reload&redirect=<% this.requestpath %>">reload AppDoc +
  • ">Application +
  • ?action=index">Index +
  • + +

    +

    + Prototypes:
    + <% this.prototypes skin="navig" %> +

    + diff --git a/DocFunction/functions.js b/DocFunction/functions.js new file mode 100644 index 00000000..4fac6021 --- /dev/null +++ b/DocFunction/functions.js @@ -0,0 +1,20 @@ + +/** + * overrides the internal href-function, as + * helma.framework.core.Application.getNodeHref(Object,String) + * isn't able to compute correct urls for non-node objects. + * @arg action of prototype + */ +function href(action) { + var url = getProperty("baseURI"); + url = (url==null || url=="null") ? "" : url; + url += this.getParentElement().getParentElement().getName() + "/api/" + this.getParentElement().getName() + "/" + this.getTypeName().toLowerCase()+"_"+this.name + "/" + ( (action!=null && action!="") ? action : "main" ); + return url; +} + + +function getApplication() { + return this.getParentElement().getParentElement(); +} + + diff --git a/DocFunction/indexList.skin b/DocFunction/indexList.skin new file mode 100644 index 00000000..3c0bc71f --- /dev/null +++ b/DocFunction/indexList.skin @@ -0,0 +1,5 @@ + + <% this.name %> + <% this.typename %> in <% this.prototypename %> + ("><% this.prototypename %>/<% this.location %>) + diff --git a/DocFunction/indexListSeparator.skin b/DocFunction/indexListSeparator.skin new file mode 100644 index 00000000..f8d0edd0 --- /dev/null +++ b/DocFunction/indexListSeparator.skin @@ -0,0 +1,3 @@ + +  <% param.letter %> + diff --git a/DocFunction/listElementAction.skin b/DocFunction/listElementAction.skin new file mode 100644 index 00000000..67c5da69 --- /dev/null +++ b/DocFunction/listElementAction.skin @@ -0,0 +1,7 @@ + + +  <% param.group %> +
    + "><% this.name %>
    <% this.comment %>
    <% this.tags %>
    + + diff --git a/DocFunction/listElementFunction.skin b/DocFunction/listElementFunction.skin new file mode 100644 index 00000000..b692f1ca --- /dev/null +++ b/DocFunction/listElementFunction.skin @@ -0,0 +1,7 @@ + + +  <% param.group %> +
    + "><% this.name %>(<% this.args %>) in <% docprototype.name %>/<% this.location %>
    <% this.comment %>
    <% this.tags %>
    + + diff --git a/DocFunction/listElementMacro.skin b/DocFunction/listElementMacro.skin new file mode 100644 index 00000000..52a10dbd --- /dev/null +++ b/DocFunction/listElementMacro.skin @@ -0,0 +1,9 @@ + + +  <% param.group %> +
    + "><% docprototype.name %>.<% this.name %> + in <% docprototype.name %>/<% this.location %> +
    <% this.comment %>
    <% this.tags %>
    + + diff --git a/DocFunction/listElementSkin.skin b/DocFunction/listElementSkin.skin new file mode 100644 index 00000000..71185419 --- /dev/null +++ b/DocFunction/listElementSkin.skin @@ -0,0 +1,7 @@ + + +  <% param.group %> +
    + "><% docprototype.name %>.<% this.name %>
    <% this.comment %>
    <% this.tags %>
    + + diff --git a/DocFunction/listElementTemplate.skin b/DocFunction/listElementTemplate.skin new file mode 100644 index 00000000..81893dd8 --- /dev/null +++ b/DocFunction/listElementTemplate.skin @@ -0,0 +1,7 @@ + + +  <% param.group %> +
    + "><% this.name %>()
    <% this.comment %>
    <% this.tags %>
    + + diff --git a/DocFunction/macros.js b/DocFunction/macros.js new file mode 100644 index 00000000..2f58e1ce --- /dev/null +++ b/DocFunction/macros.js @@ -0,0 +1,136 @@ +/** + * macro rendering a skin + * @param name name of skin + */ +function skin_macro(par) { + if ( par && par.name ) { + this.renderSkin(par.name); + } +} + + +/** + * macro-wrapper for href-function + * @param action name of action to call on this prototype, default main + */ +function href_macro(par) { + return this.href( (par&&par.action)?par.action:"main" ); +} + + +/** + * macro returning name of file this method resides in + */ +function location_macro(par) { + var f = new File ( this.getLocation() ); + return f.getName(); +} + + +/** + * macro returning the type of this method (Action, Template, Skin, Macro, Function) + */ +function typename_macro(par) { + return this.getTypeName(); +} + + +/** + * macro returning a link to the prototype page + * @param action name of action to call on this prototype, default main + */ +function prototypehref_macro(par) { + return this.getDocPrototype().href( (par&&par.action)?par.action:"main" ) +} + + +/** + * macro returning the name of the prototype this method belongs to + */ +function prototypename_macro(par) { + return this.getDocPrototype().getName(); +} + + +/** + * macro returning the comment text of this method + * (excluding the tags!) + * @param size (optional) text is cutoff after a number of chars + */ +function comment_macro(par) { + var str = this.getComment(); + if ( par && par.length && str.length > par.size ) { + return ( str.substring(0,par.size) ); + } else { + return ( str ); + } +} + + +/** + * macro rendering the list of tags + */ +function tags_macro() { + var arr = this.listTags(); + var argCt = 0; + for ( var i in arr ) { + if ( arr[i].getKind()==Packages.helma.doc.DocTag.ARG ) + argCt++; + res.write( arr[i].render(argCt,this) ); + } +} + + +/** + * macro rendering sequence of arg1, arg2 etc + * according to number of arguments in doctags. + */ +function args_macro() { + var ct = this.countTags(Packages.helma.doc.DocTag.ARG); + for ( var i=0; i"); + var str4 = ""; + for ( var i=0; i ' + if ( i<100 ) str4+=' '; + str4 += arr[i] + "
    "; + } + return ( str4 ); +} + + +/** + * macro returning the fullname of this method + */ +function fullname_macro(par) { + return this.getFullName(); +} + + diff --git a/DocFunction/main.hac b/DocFunction/main.hac new file mode 100644 index 00000000..ef413f29 --- /dev/null +++ b/DocFunction/main.hac @@ -0,0 +1,8 @@ +if ( checkAddress()==false ) return; +if ( checkAuth(this)==false ) return; + +res.body = this.renderSkinAsString("main"); +res.skin = "api"; +res.title = "Application " + this.name; + + diff --git a/DocFunction/main.skin b/DocFunction/main.skin new file mode 100644 index 00000000..29a7bc8f --- /dev/null +++ b/DocFunction/main.skin @@ -0,0 +1,14 @@ + + +

    + ">Prototype <% docprototype.name %>
    + <% this.fullname %> +

    + +
    + in <% docprototype.name%>/<% this.location %>: +
    + + +
    <% this.source %>
    + diff --git a/DocPrototype/appList.skin b/DocPrototype/appList.skin new file mode 100644 index 00000000..e132ca63 --- /dev/null +++ b/DocPrototype/appList.skin @@ -0,0 +1,10 @@ + + +  Prototype +
    + "><% this.name %>
    + <% this.comment %> +
    + + + diff --git a/DocPrototype/functions.js b/DocPrototype/functions.js new file mode 100644 index 00000000..053c0541 --- /dev/null +++ b/DocPrototype/functions.js @@ -0,0 +1,14 @@ + +/** + * overrides the internal href-function, as + * helma.framework.core.Application.getNodeHref(Object,String) + * isn't able to compute correct urls for non-node objects. + * @arg action of prototype + */ +function href(action) { + var url = getProperty("baseURI"); + url = (url==null || url=="null") ? "" : url; + url += this.getParentElement().getName() + "/api/" + this.name + "/" + ( (action!=null && action!="") ? action : "main" ); + return url; +} + diff --git a/DocPrototype/listFooter.skin b/DocPrototype/listFooter.skin new file mode 100644 index 00000000..d3f6097b --- /dev/null +++ b/DocPrototype/listFooter.skin @@ -0,0 +1,3 @@ + +
    + diff --git a/DocPrototype/listHeader.skin b/DocPrototype/listHeader.skin new file mode 100644 index 00000000..bbe57421 --- /dev/null +++ b/DocPrototype/listHeader.skin @@ -0,0 +1,7 @@ + + + + + + + diff --git a/DocPrototype/macros.js b/DocPrototype/macros.js new file mode 100644 index 00000000..3db36027 --- /dev/null +++ b/DocPrototype/macros.js @@ -0,0 +1,90 @@ +/** + * macro rendering a skin + * @param name name of skin + */ +function skin_macro(par) { + if ( par && par.name ) { + this.renderSkin(par.name); + } +} + + +/** + * macro-wrapper for href-function + * @param action name of action to call on this prototype, default main + */ +function href_macro(par) { + return this.href( (par&&par.action)?par.action:"main" ); +} + + +/** + * macro returning the comment for this prototype + */ +function comment_macro(par) { + return this.getComment(); +} + + +/** + * macro formatting list of actions of this prototype + */ +function actions_macro(par) { + this.printMethods( Packages.helma.doc.DocElement.ACTION, "listElementAction","Actions" ); +} + + +/** + * macro formatting list of templates of this prototype + */ +function templates_macro(par) { + this.printMethods( Packages.helma.doc.DocElement.TEMPLATE, "listElementTemplate","Templates" ); +} + + +/** + * macro formatting list of functions of this prototype + */ +function functions_macro(par) { + this.printMethods( Packages.helma.doc.DocElement.FUNCTION, "listElementFunction","Functions" ); +} + + +/** + * macro formatting list of skins of this prototype + */ +function skins_macro(par) { + this.printMethods( Packages.helma.doc.DocElement.SKIN, "listElementSkin","Skins" ); +} + + +/** + * macro formatting list of macros of this prototype + */ +function macros_macro(par) { + this.printMethods( Packages.helma.doc.DocElement.MACRO, "listElementMacro","Macros" ); +} + + +/** + * macro-utility: renders a list of methods of this prototype + * usage of docprototype.listHeader/listFooter skin is hardcoded + * @arg type integer - which type of methods are listed + * @arg skin skin to be called on method + * @arg desc string describing the type of method (ie "Skins", "Actions") + */ +function printMethods(type,skin,desc) { + var arr = this.listFunctions(type); + if ( arr.length > 0 ) { + var obj = new Object(); + obj.desc = desc; + this.renderSkin("listHeader",obj); + for ( var i in arr ) { + arr[i].renderSkin(skin,obj); + } + this.renderSkin("listFooter",obj); + } +} + + + diff --git a/DocPrototype/main.hac b/DocPrototype/main.hac new file mode 100644 index 00000000..ef413f29 --- /dev/null +++ b/DocPrototype/main.hac @@ -0,0 +1,8 @@ +if ( checkAddress()==false ) return; +if ( checkAuth(this)==false ) return; + +res.body = this.renderSkinAsString("main"); +res.skin = "api"; +res.title = "Application " + this.name; + + diff --git a/DocPrototype/main.skin b/DocPrototype/main.skin new file mode 100644 index 00000000..71821440 --- /dev/null +++ b/DocPrototype/main.skin @@ -0,0 +1,9 @@ + +

    Prototype <% this.name %>

    + +<% this.actions %> +<% this.skins %> +<% this.macros %> +<% this.functions %> +<% this.templates %> + diff --git a/DocPrototype/navig.skin b/DocPrototype/navig.skin new file mode 100644 index 00000000..cc6f041f --- /dev/null +++ b/DocPrototype/navig.skin @@ -0,0 +1,2 @@ + +"><% this.name %>
    diff --git a/DocTag/renderfunctions.js b/DocTag/renderfunctions.js new file mode 100644 index 00000000..ede11b25 --- /dev/null +++ b/DocTag/renderfunctions.js @@ -0,0 +1,46 @@ +/** + * function renders list of tags, language is hardcoded here + * @arg number of current argument (for formatting arg1, arg2 etc) + * @arg method method-object from which we try to find other prototypes/methods + * when we're formatting a see tag + */ +function render(argCt,docFunc) { + var str = ""; + if ( this.getKind() == this.ARG ) { + str = "arg" + argCt + ": " + format(this.text); + } else if ( this.getKind() == this.PARAM ) { + str = "Parameter " + this.name; + if ( this.text!=null && this.text!="" ) { + str += ": " + format(this.text); + } + } else if ( this.getKind() == this.RETURNS ) { + str = "Returns: " + format(this.text); + } else if ( this.getKind() == this.AUTHOR ) { + str = "by " + format(this.text) + ""; + } else if ( this.getKind() == this.VERSION ) { + str = "Version " + format(this.text) + ""; + } else if ( this.getKind() == this.RELEASE ) { + str = "since" + format(this.text) + ""; + } else if ( this.getKind() == this.SEE ) { + if ( this.text.indexOf("http://")==0 ) { + str = '' + this.text + ''; + } else { + var tmp = new java.lang.String(this.text); + tmp = tmp.trim(); + var arr = tmp.split("."); + var obj = docFunc.getApplication().getDocPrototype(arr[0]); + if( arr.length>1 && obj.getFunction(arr[1])!=null ) { + str = 'See also: ' + format(tmp) + ''; + } else if ( obj!=null ) { + str = 'See also: ' + format(tmp) + ''; + } + } + if ( str=="" ) { + str = "See also: " + format(this.text); + } + } + return str + "
    "; +} + + + diff --git a/Global/api.skin b/Global/api.skin new file mode 100644 index 00000000..d152e04d --- /dev/null +++ b/Global/api.skin @@ -0,0 +1,17 @@ + + +<% skin name="head" %> + + +
    <% param.desc %>
    + + + + +
    +

    ">" title="helma" border="0" width="174" height="35" align="baseline" style="border-width:3px;border-color:white;">

    + <% docapplication.skin name="navig" %>
    <% response.body %>
    + + + + diff --git a/Global/functions.js b/Global/functions.js new file mode 100644 index 00000000..62858d0b --- /dev/null +++ b/Global/functions.js @@ -0,0 +1,155 @@ + + +/** + * scheduler function, runs global.appStat every minute + */ +function scheduler() { + appStat(); + return 60000; +} + + +/** + * initializes requestStat storage on startup + */ +function onStart() { + app.requestStat = new HopObject(); + app.addressFilter = new Packages.helma.util.InetAddressFilter(); + var str = root.getProperty("allowadmin"); + if ( str!=null && str!="" ) { + var arr = str.split(","); + for ( var i in arr ) { + var str = new java.lang.String(arr[i]); + app.addressFilter.addAddress(str.trim()); + } + } +} + + +/** + * updates the request stats in app.requestStat every 5 minutes + */ +function appStat() { + if ( app.requestStat==null ) { + app.requestStat = new HopObject(); + } + if( (new Date()-300000) < app.requestStat.lastRun ) { + return; + } + var arr = root.getApplications(); + for ( var i=0; ib.name ) + return 1; + else if ( a.name==b.name ) + return 0; + else + return -1; +} + + +/** + * utility function to sort property-arrays by key + */ +function sortProps(a,b) { + if ( a>b ) + return 1; + else if ( a==b ) + return 0; + else + return -1; +} + +/** + * check access to an application or the whole server, authenticate against md5-encrypted + * properties of base-app or the particular application. if username or password aren't set + * go into stealth-mode and return a 404. if username|password are wrong, prepare response- + * object for http-auth and return false. + * @arg application-object + */ +function checkAuth(appObj) { + var ok = false; + + // check against root + var rootUsername = root.getProperty("adminusername"); + var rootPassword = root.getProperty("adminpassword"); + + if ( rootUsername==null || rootUsername=="" || rootPassword==null || rootPassword=="" ) + return forceStealth(); + + var uname = req.getUsername(); + var pwd = req.getPassword(); + + if ( uname==null || uname=="" || pwd==null || pwd=="" ) + return forceAuth(); + + var md5password = calcMD5(uname); + var md5username = calcMD5(pwd); + + if ( md5username==rootUsername && md5password==rootPassword ) + return true; + + if ( appObj!=null && appObj.isActive() ) { + // check against application + var appUsername = appObj.getProperty("adminusername"); + var appPassword = appObj.getProperty("adminpassword"); + if ( appUsername==null || appUsername=="" || appPassword==null || appPassword=="" ) + return forceStealth(); + if ( md5username==appUsername && md5password==appPassword ) + return true; + } + return forceAuth(); +} + + +/** + * check access to the base-app by ip-addresses + */ +function checkAddress() { + if ( !app.addressFilter.matches(java.net.InetAddress.getByName(req.data.http_remotehost)) ) + return forceStealth(); + else + return true; +} + + +/** + * response is reset to 401 / authorization required + */ +function forceAuth(appObj) { + res.status = 401; + res.realm = (appObj==null) ? "helma" : appObj.name; + res.reset(); + res.write ("Authorization Required. The server could not verify that you are authorized to access the requested page."); + return false; +} + +/** + * response is reset to 404 / notfound + */ +function forceStealth() { + res.reset(); + res.status = 404; + return false; +} + + + diff --git a/Global/global.skin b/Global/global.skin new file mode 100644 index 00000000..a80b0da1 --- /dev/null +++ b/Global/global.skin @@ -0,0 +1,14 @@ + + +<% skin name="head" %> + + + + + + + +
    <% skin name="navig" %><% response.body %>
    + + + diff --git a/Global/head.skin b/Global/head.skin new file mode 100644 index 00000000..4f5659c0 --- /dev/null +++ b/Global/head.skin @@ -0,0 +1,53 @@ + + <% response.title %> + + \ No newline at end of file diff --git a/Global/macros.js b/Global/macros.js new file mode 100644 index 00000000..5f0b72c5 --- /dev/null +++ b/Global/macros.js @@ -0,0 +1,97 @@ +/** + * macro rendering a skin + * @param name name of skin + */ +function skin_macro(par) { + if ( par && par.name ) { + renderSkin(par.name); + } +} + + +/** + * Macro returning the actual date and time. + */ +function now_macro() { + var date = new Date(); + return(date.format("dd.MM.yyyy, HH:mm'h' zzz")); +} + + +/** + * macro-utility: formatting property lists + */ +function formatProperties(props,par) { + var prefix = (par && par.prefix) ? par.prefix : ""; + var suffix = (par && par.suffix) ? par.suffix : ""; + var separator = (par && par.separator) ? par.separator : ""; + var e = props.keys(); + var arr = new Array(); + if ( e==null ) + return ""; + while ( e.hasMoreElements() ) { + arr[arr.length] = e.nextElement(); + } + arr.sort(sortProps); + for ( var i in arr ) { + // don't print the admin-password + if ( arr[i].toLowerCase()=="adminusername" || arr[i].toLowerCase()=="adminpassword" ) continue; + res.write ( prefix + arr[i] + separator + props.getProperty(arr[i]) + suffix ); + } +} + + +/** + * macro-utility: formatting an integer value as human readable bytes + */ +function formatBytes(bytes) { + if ( bytes > Math.pow(2,30) ) { + res.write( Math.round( 100*bytes/Math.pow(2,30) ) / 100 + "gb" ); + } else if ( bytes > Math.pow(2,20) ) { + res.write( Math.round( 100*bytes/Math.pow(2,20) ) / 100 + "mb" ); + } else { + res.write( Math.round( 100*bytes/Math.pow(2,10) ) / 100 + "kb" ); + } +} + + +/** + * macro-utility: formatting time in millis as human readable age + */ +function formatAge(age) { + var str = ""; + var days = Math.floor(age/86400); + var age = age - days * 86400; + var hours = Math.floor(age / 3600); + var age = age - hours * 3600; + var minutes = Math.floor(age / 60); + var seconds = Math.floor(age - minutes * 60); + if (days > 0) + str += (days + " days, "); + if (hours>0) + str += (hours + "h, "); + str += (minutes + "min"); + if (days == 0) str += (", " + seconds + "sec"); + return(str); +} + + +/** + * macro-utility: formatting a number-suffix by choosing between singular and plural + * @arg value number to be formatted + * @arg param-object object to get fields + * @param singular string used for value==1 + * @param plural string used for value!=1 + */ +function formatCount(ct, par) { + if ( !par || !par.singular || !par.plural ) { + return ""; + } + if ( ct==1 ) + return par.singular; + else + return par.plural; +} + + + diff --git a/Global/md5.js b/Global/md5.js new file mode 100644 index 00000000..3d31a709 --- /dev/null +++ b/Global/md5.js @@ -0,0 +1,178 @@ +/* + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message + * Digest Algorithm, as defined in RFC 1321. + * Copyright (C) Paul Johnston 1999 - 2000. + * Updated by Greg Holt 2000 - 2001. + * See http://pajhome.org.uk/site/legal.html for details. + */ + + +/** + * Take a string and return the hex representation of its MD5. + * @arg string + */ +function calcMD5(str) +{ + x = str2blks_MD5(str); + a = 1732584193; + b = -271733879; + c = -1732584194; + d = 271733878; + + for(i = 0; i < x.length; i += 16) + { + olda = a; + oldb = b; + oldc = c; + oldd = d; + + a = ff(a, b, c, d, x[i+ 0], 7 , -680876936); + d = ff(d, a, b, c, x[i+ 1], 12, -389564586); + c = ff(c, d, a, b, x[i+ 2], 17, 606105819); + b = ff(b, c, d, a, x[i+ 3], 22, -1044525330); + a = ff(a, b, c, d, x[i+ 4], 7 , -176418897); + d = ff(d, a, b, c, x[i+ 5], 12, 1200080426); + c = ff(c, d, a, b, x[i+ 6], 17, -1473231341); + b = ff(b, c, d, a, x[i+ 7], 22, -45705983); + a = ff(a, b, c, d, x[i+ 8], 7 , 1770035416); + d = ff(d, a, b, c, x[i+ 9], 12, -1958414417); + c = ff(c, d, a, b, x[i+10], 17, -42063); + b = ff(b, c, d, a, x[i+11], 22, -1990404162); + a = ff(a, b, c, d, x[i+12], 7 , 1804603682); + d = ff(d, a, b, c, x[i+13], 12, -40341101); + c = ff(c, d, a, b, x[i+14], 17, -1502002290); + b = ff(b, c, d, a, x[i+15], 22, 1236535329); + + a = gg(a, b, c, d, x[i+ 1], 5 , -165796510); + d = gg(d, a, b, c, x[i+ 6], 9 , -1069501632); + c = gg(c, d, a, b, x[i+11], 14, 643717713); + b = gg(b, c, d, a, x[i+ 0], 20, -373897302); + a = gg(a, b, c, d, x[i+ 5], 5 , -701558691); + d = gg(d, a, b, c, x[i+10], 9 , 38016083); + c = gg(c, d, a, b, x[i+15], 14, -660478335); + b = gg(b, c, d, a, x[i+ 4], 20, -405537848); + a = gg(a, b, c, d, x[i+ 9], 5 , 568446438); + d = gg(d, a, b, c, x[i+14], 9 , -1019803690); + c = gg(c, d, a, b, x[i+ 3], 14, -187363961); + b = gg(b, c, d, a, x[i+ 8], 20, 1163531501); + a = gg(a, b, c, d, x[i+13], 5 , -1444681467); + d = gg(d, a, b, c, x[i+ 2], 9 , -51403784); + c = gg(c, d, a, b, x[i+ 7], 14, 1735328473); + b = gg(b, c, d, a, x[i+12], 20, -1926607734); + + a = hh(a, b, c, d, x[i+ 5], 4 , -378558); + d = hh(d, a, b, c, x[i+ 8], 11, -2022574463); + c = hh(c, d, a, b, x[i+11], 16, 1839030562); + b = hh(b, c, d, a, x[i+14], 23, -35309556); + a = hh(a, b, c, d, x[i+ 1], 4 , -1530992060); + d = hh(d, a, b, c, x[i+ 4], 11, 1272893353); + c = hh(c, d, a, b, x[i+ 7], 16, -155497632); + b = hh(b, c, d, a, x[i+10], 23, -1094730640); + a = hh(a, b, c, d, x[i+13], 4 , 681279174); + d = hh(d, a, b, c, x[i+ 0], 11, -358537222); + c = hh(c, d, a, b, x[i+ 3], 16, -722521979); + b = hh(b, c, d, a, x[i+ 6], 23, 76029189); + a = hh(a, b, c, d, x[i+ 9], 4 , -640364487); + d = hh(d, a, b, c, x[i+12], 11, -421815835); + c = hh(c, d, a, b, x[i+15], 16, 530742520); + b = hh(b, c, d, a, x[i+ 2], 23, -995338651); + + a = ii(a, b, c, d, x[i+ 0], 6 , -198630844); + d = ii(d, a, b, c, x[i+ 7], 10, 1126891415); + c = ii(c, d, a, b, x[i+14], 15, -1416354905); + b = ii(b, c, d, a, x[i+ 5], 21, -57434055); + a = ii(a, b, c, d, x[i+12], 6 , 1700485571); + d = ii(d, a, b, c, x[i+ 3], 10, -1894986606); + c = ii(c, d, a, b, x[i+10], 15, -1051523); + b = ii(b, c, d, a, x[i+ 1], 21, -2054922799); + a = ii(a, b, c, d, x[i+ 8], 6 , 1873313359); + d = ii(d, a, b, c, x[i+15], 10, -30611744); + c = ii(c, d, a, b, x[i+ 6], 15, -1560198380); + b = ii(b, c, d, a, x[i+13], 21, 1309151649); + a = ii(a, b, c, d, x[i+ 4], 6 , -145523070); + d = ii(d, a, b, c, x[i+11], 10, -1120210379); + c = ii(c, d, a, b, x[i+ 2], 15, 718787259); + b = ii(b, c, d, a, x[i+ 9], 21, -343485551); + + a = add(a, olda); + b = add(b, oldb); + c = add(c, oldc); + d = add(d, oldd); + } + return rhex(a) + rhex(b) + rhex(c) + rhex(d); +} + + + +/* + * Convert a 32-bit number to a hex string with ls-byte first + */ +var hex_chr = "0123456789abcdef"; +function rhex(num) +{ + str = ""; + for(j = 0; j <= 3; j++) + str += hex_chr.charAt((num >> (j * 8 + 4)) & 0x0F) + + hex_chr.charAt((num >> (j * 8)) & 0x0F); + return str; +} + +/* + * Convert a string to a sequence of 16-word blocks, stored as an array. + * Append padding bits and the length, as described in the MD5 standard. + */ +function str2blks_MD5(str) +{ + nblk = ((str.length + 8) >> 6) + 1; + blks = new Array(nblk * 16); + for(i = 0; i < nblk * 16; i++) blks[i] = 0; + for(i = 0; i < str.length; i++) + blks[i >> 2] |= str.charCodeAt(i) << ((i % 4) * 8); + blks[i >> 2] |= 0x80 << ((i % 4) * 8); + blks[nblk * 16 - 2] = str.length * 8; + return blks; +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function add(x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/* + * Bitwise rotate a 32-bit number to the left + */ +function rol(num, cnt) +{ + return (num << cnt) | (num >>> (32 - cnt)); +} + +/* + * These functions implement the basic operation for each round of the + * algorithm. + */ +function cmn(q, a, b, x, s, t) +{ + return add(rol(add(add(a, q), add(x, t)), s), b); +} +function ff(a, b, c, d, x, s, t) +{ + return cmn((b & c) | ((~b) & d), a, b, x, s, t); +} +function gg(a, b, c, d, x, s, t) +{ + return cmn((b & d) | (c & (~d)), a, b, x, s, t); +} +function hh(a, b, c, d, x, s, t) +{ + return cmn(b ^ c ^ d, a, b, x, s, t); +} +function ii(a, b, c, d, x, s, t) +{ + return cmn(c ^ (b | (~d)), a, b, x, s, t); +} diff --git a/Global/navig.skin b/Global/navig.skin new file mode 100644 index 00000000..87cc3ae5 --- /dev/null +++ b/Global/navig.skin @@ -0,0 +1,17 @@ +

    ">" title="helma" border="0" width="174" height="35" align="baseline" style="border-width:3px;border-color:white;">

    + + +
    + <% root.appCount filter="active" singular=" app" plural=" apps"%> on <% root.hostname %> +
    + +<% root.appList filter="active" %> + +

    + +
    + and <% root.appCount filter="disabled" %> disabled apps: +
    + +<% root.appList filter="disabled" skin="navig_disabled" %> + diff --git a/Root/functions.js b/Root/functions.js new file mode 100644 index 00000000..55a0baea --- /dev/null +++ b/Root/functions.js @@ -0,0 +1,36 @@ + +/** + * lists all applications in appdir. + * for active apps use this.getApplications() = helma.main.Server.getApplications() + */ +function getAllApplications() { + var appsDir = this.getAppsHome(); + var dir = appsDir.list(); + var arr = new Array(); + for ( var i=0; i str.lastIndexOf('/') ) ? str.lastIndexOf('\\') : str.lastIndexOf('/'); + res.write ( arr[i].substring(pos+1) + ".jar" ); + if ( i < arr.length-1 ) res.write ( separator ); + } +} + + +/** + * Macro that returns the name and version of the server's os + */ +function os_macro() { + return java.lang.System.getProperty("os.name") + " " + java.lang.System.getProperty("os.arch") + " " + java.lang.System.getProperty("os.version"); +} + + +/** + * Macro that returns anything from server.properties + */ +function property_macro(par) { + if ( par && par.key ) { + return this.getProperty(key); + } else { + return ""; + } +} + + +/** + * Macro formatting server.properties + */ +function properties_macro(par) { + formatProperties(this.getProperties(),par); +} + + +/** + * Macro that returns the timezone of this server + */ +function timezone_macro(par) { + return java.util.TimeZone.getDefault().getDisplayName(false, java.util.TimeZone.LONG) + " (" + java.util.TimeZone.getDefault().getID() + ")"; +} + + diff --git a/Root/main.hac b/Root/main.hac new file mode 100644 index 00000000..5cb4d0e3 --- /dev/null +++ b/Root/main.hac @@ -0,0 +1,46 @@ + +/** + * main action, show server-stats + * perform start, stop, restart and flush-action + * + */ + + +if ( checkAddress()==false ) return; + +if ( req.data.app!=null && req.data.app!="" && req.data.action!=null && req.data.action!="" ) { + + var appObj = root.getApp(req.data.app); + // check access for application. md5-encoded uname/pwd can also be put in + // app.properties to limit access to a single app + if ( checkAuth(appObj)==false ) return; + + if ( req.data.action=="start" ) { + this.startApplication(req.data.app); + res.redirect ( appObj.href("main") ); + + } else if ( req.data.action=="stop" ) { + if ( checkAuth()==false ) return; + this.stopApplication(req.data.app); + res.redirect ( root.href("main") ); + + } else if ( req.data.action=="restart" ) { + this.stopApplication(req.data.app); + this.startApplication(req.data.app); + res.redirect ( appObj.href("main") ); + + } else if ( req.data.action=="flush" ) { + appObj.clearAppCache(); + res.redirect ( appObj.href("main") ); + + } + +} + +// output only to root +if ( checkAuth()==false ) return; + +res.skin = "global"; +res.title = "Helma Object Publisher - Serverinfo"; +res.body = this.renderSkinAsString("main"); + diff --git a/Root/main.skin b/Root/main.skin new file mode 100644 index 00000000..f3e7910b --- /dev/null +++ b/Root/main.skin @@ -0,0 +1,101 @@ +<% this.hostname %> (<% this.hostaddress %>)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<% this.properties prefix="" %> +
    helma
    uptime: <% this.uptime %>
    version: <% this.version %>
    homedir: <% this.home %>
    total active sessions <% this.countSessions %>
    total request 5-min-avg <% this.countRequests %>
    jre
    free memory: <% this.jvmFreeMemory %>
    used memory: <% this.jvmUsedMemory %>
    total memory: <% this.jvmTotalMemory %>
    java: <% this.jvm %>
    javahome: <% this.jvmHome %>
    os: <% this.os %>
    localtime: <% now %>
    timezone: <% this.timezone %>
    loaded Jars: <% this.jvmJars %>
    server.properties
    " separator=" " suffix="
    + + + + diff --git a/Root/makekey.hac b/Root/makekey.hac new file mode 100644 index 00000000..cadf28c0 --- /dev/null +++ b/Root/makekey.hac @@ -0,0 +1,10 @@ + +if ( checkAddress()==false ) return; +if ( checkAuth()==false ) return; + +if ( req.data.value!=null ) { + res.write ( calcMD5(req.data.value) ); +} else { + res.write ( '
    ' ); +} + diff --git a/app.properties b/app.properties new file mode 100644 index 00000000..544f3805 --- /dev/null +++ b/app.properties @@ -0,0 +1,5 @@ +# Set this property according to your +# server configuration: + +baseURI = /manage/ + diff --git a/class.properties b/class.properties new file mode 100644 index 00000000..181c3887 --- /dev/null +++ b/class.properties @@ -0,0 +1,11 @@ +# +# Map Java classes to the prototype used to script them +# + +helma.main.Server = root +helma.framework.core.Application = application +helma.doc.DocApplication = docapplication +helma.doc.DocPrototype = docprototype +helma.doc.DocFunction = docfunction +helma.doc.DocTag = doctag +