chg: replaced ant with gradle

This commit is contained in:
Tobi Schäfer 2020-03-16 16:53:52 +01:00
parent cee0be52e0
commit 5cbeb9f01d
609 changed files with 87626 additions and 638 deletions

23
src/dist/apps.properties vendored Normal file
View file

@ -0,0 +1,23 @@
# List of applications to start.
# More information about this file is available at
# http://helma.org/Documentation/Properties+Files/apps.properties/
# Administrative application to manage all other apps on this server,
# accessible via its default mountpoint at http://<host>:<port>/manage
# and using its default repository at apps/manage
manage
# More complex example of an application with custom configuration:
welcome
welcome.mountpoint = /
welcome.repository.0 = apps/welcome/code/
welcome.repository.1 = modules/tools
welcome.static = apps/welcome/static
welcome.staticMountpoint = /static
welcome.staticHome = index.html,default.html
welcome.staticIndex = true
welcome.uploadLimit = 2048

View file

@ -0,0 +1,67 @@
/**
* renders AppManager
*/
function main_action() {
if (checkAddress() == false)
return;
if (checkAuth(this) == false)
return;
res.data.body = this.renderSkinAsString("main");
renderSkin("global");
}
/**
* 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 but checks the
* remote address.
*/
function mrtg_action() {
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());
res.write("\n0\n0\n0\n");
} else if (req.data.action == "threads") {
res.write(this.countActiveEvaluators() + "\n");
res.write(this.countEvaluators() + "\n");
res.write("0\n0\n");
} else if (req.data.action == "cache") {
res.write(this.getCacheUsage() + "\n");
res.write(this.getProperty("cachesize", "1000") + "\n");
res.write("0\n0\n");
} else if (req.data.action == "requests") {
// res.write (
} else {
res.write("0\n0\n0\n0\n");
}
}
/**
* performs a redirect to the public site
* (workaround, we can't access application object from docapplication for some reason)
* @see application.url_macro
*/
function redirectpublic_action() {
if (checkAddress() == false) return;
if (checkAuth(this) == false) return;
res.redirect(this.url_macro());
}

View file

@ -0,0 +1,42 @@
/**
* construct an application object so that we can use
* skins for non-active applications too
* @arg name
*/
function constructor(name) {
this.name = name;
}
/**
* return true/false to determine if application is running
*/
function isActive() {
if (root.getApplication(this.name) == null)
return false;
else
return true;
}
/**
* Method used by Helma for URL composition.
*/
function href(action) {
var base = root.href() + this.name + "/";
return action ? base + action : base;
}
/**
* Method used by Helma for URL composition.
*/
function getParentElement() {
return root;
}
/**
* Method used by Helma request path resolution.
*/
function getChildElement(name) {
if (name == "api")
return this.getDoc();
return null;
}

View file

@ -0,0 +1,11 @@
<p><big>AppManager <% this.title %></big>
<% this.description prefix="<br/>" %>
<br/>
-&gt;
<a href="<% this.href action="api" %>/read">showAPI</a> |
<a href="<% this.href action="api" %>/render">renderAPI</a> |
<a href="<% this.url %>">public</a> |
<a href="<% root.href action="main" %>?app=<% this.title %>&action=flush">flush</a> |
<a href="<% root.href action="main" %>?app=<% this.title %>&action=restart">restart</a> |
<a href="<% root.href action="main" %>?app=<% this.title %>&action=stop">stop</a>
</p>

View file

@ -0,0 +1,210 @@
/**
* 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 users = this.activeUsers.iterator();
while (users.hasNext()) {
res.write(users.next().__name__);
if (users.hasNext()) {
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 returning the current number of objects in the cache
*/
function cacheusage_macro(param) {
return this.getCacheUsage();
}
/**
* Macro returning the number of objects allowed in the cache
*/
function cachesize_macro(param) {
return this.getProperty("cachesize", "1000");
}
/**
* Macro formatting the number of requests in the last 5 minutes
*/
function requestCount_macro(par) {
if (app.data.stat == null || app.data.stat[this.name] == null)
return "not available";
if (this.isActive()) {
var obj = app.data.stat[this.name];
return obj.requestCount + formatCount(obj.requestCount, par);
} else {
return 0 + formatCount(0, par);
}
}
/**
* Macro formatting the number of errors in the last 5 minutes
*/
function errorCount_macro(par) {
if (app.data.stat == null || app.data.stat[this.name] == null)
return "not available";
if (this.isActive()) {
var obj = app.data.stat[this.name];
return obj.errorCount + formatCount(obj.errorCount, par);
} else {
return 0 + formatCount(0, par);
}
}
/**
* Macro formatting app.properties
*/
function properties_macro(par) {
formatProperties(this.getProperties(), par);
}
function repositories_macro(param) {
var repos = this.getRepositories().iterator();
while (repos.hasNext())
res.writeln(repos.next().getName());
}

View file

@ -0,0 +1,62 @@
<% this.skin name="head" %>
<table width="100%" border="0" cellspacing="0" cellpadding="3">
<tr>
<td class="list_separator" colspan="3">application</td>
</tr>
</table>
<table border="0" cellspacing="0" cellpadding="3">
<tr>
<td class="list_property" align="left">active sessions</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.countSessions %></td>
</tr>
<tr>
<td class="list_property" align="left"><a href="<% this.href action="main" %>?showusers=true">logged-in users</a></td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.users %>&nbsp;</td>
</tr>
<tr>
<td class="list_property" align="left">active evaluators</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.countActiveEvaluators %></td>
</tr>
<tr>
<td class="list_property" align="left">free evaluators</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.countFreeEvaluators %></td>
</tr>
<tr>
<td class="list_property" align="left">requests / 5 min</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.requestCount %></td>
</tr>
<tr>
<td class="list_property" align="left">errors / 5 min</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.errorCount %></td>
</tr>
<tr>
<td class="list_property" align="left">cache usage</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.cacheusage %> objects of <% this.cachesize %></td>
</tr>
<tr>
<td class="list_property" align="left">uptime</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.uptime %></td>
</tr>
<tr>
<td class="list_property" align="left" valign="top">repositories</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.repositories %></td>
</tr>
</table>
<table width="100%" border="0" cellspacing="0" cellpadding="3">
<tr>
<td class="list_separator" colspan="3">app.properties</td>
</tr>
<% this.properties itemprefix='<tr><td class="list_property" valign="top">' separator='</td><td class="list_property" width="5">&nbsp;</td><td class="list_property" valign="top">' itemsuffix='</td></tr>' %>
</table>

View file

@ -0,0 +1,18 @@
<div class="list_apps">
<b><a href="<% this.href action="main" %>"><% this.title %></a></b><br />
<small><% this.countSessions singular=" Session" plural=" Sessions" %>,
<% this.requestCount singular=" Request" plural=" Requests" %>/5min</small>
<div align="right">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td align="right" valign="top"><small style="font-size:9px;">
<a href="<% this.href action="api" %>/read">showAPI</a> |
<a href="<% this.href action="api" %>/render">renderAPI</a> |
<a href="<% this.url %>">public</a> |
<a href="<% root.href action="main" %>?app=<% this.title %>&action=flush">flush</a> |
<a href="<% root.href action="main" %>?app=<% this.title %>&action=restart">restart</a>
</small></td>
</tr>
</table>
</div>
</div>

View file

@ -0,0 +1,10 @@
<div class="list_apps">
<table border="0" cellspacing="0" cellpadding="0" align="right">
<tr>
<td align="right" valign="top"><small>
<a href="<% root.href action="main" %>?app=<% this.title %>&action=start">start</a>
</td>
</tr>
</table>
<b><% this.title %></b>
</div>

View file

@ -0,0 +1,59 @@
function read_action() {
this.readApplication();
res.redirect(this.href("main"));
}
function main_action() {
if (checkAddress() == false)
return;
if (checkAuth(this.getParentElement()) == false)
return;
this.renderSkin("frameset");
}
function prototypes_action() {
if (checkAddress() == false)
return;
if (checkAuth(this.getParentElement()) == false)
return;
res.data.body = this.renderSkinAsString("prototypes");
renderSkin("api");
}
function summary_action() {
if (checkAddress() == false)
return;
if (checkAuth(this.getParentElement()) == false)
return;
res.data.body = this.renderSkinAsString("summary");
renderSkin("api");
}
function functionindex_action() {
if (checkAddress() == false)
return;
if (checkAuth(this.getParentElement()) == false)
return;
res.data.body = this.renderSkinAsString("functionindex");
renderSkin("api");
}
function render_action() {
// set res.data.rendering, this will suppress the link back to the manage
// console in the apidocs actions
res.data.rendering = true;
if (checkAddress() == false)
return;
if (checkAuth(this.getParentElement()) == false)
return;
var ct = this.renderApi();
res.data.body = '<body>rendering API ...<br/>wrote ' + ct + ' files<br/><br/>';
res.data.body += '<a href="' + root.href("main") + '">back to manage console</a>';
res.data.title = "rendering helma api";
res.data.head = renderSkinAsString("head");
renderSkin("basic");
}

View file

@ -0,0 +1,31 @@
<html>
<head>
<title>helma api / <% this.name %></title>
<script language="javascript"><!--
function changePrototypeList (obj) {
if (obj.href.indexOf (".html")>-1)
var newhref = obj.href.substring (0, obj.href.length-9) + "list.html";
else
var newhref = obj.href.substring (0, obj.href.length-4) + "list";
functions.location.href = newhref;
}
//--></script>
</head>
<frameset cols="30%,70%">
<frameset rows="40%,60%">
<frame src="<% this.href action="prototypes" %>" name="prototypes">
<frame src="<% this.hrefRoot action="list" %>" name="functions">
</frameset>
<frame src="<% this.href action="summary" %>" name="main">
</frameset>
<noframes>
<h2>
Frame Alert</h2>
<p>
This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
</noframes>
</html>

View file

@ -0,0 +1,24 @@
<table width="90%" border="0" cellspacing="1" cellpadding="5">
<tr>
<td class="headline">
<big class="top">Application <% this.headline %></tt></b></big><br>
</td>
</tr>
</table>
<a class="navig" href="<% this.href action="summary"%>">SUMMARY</a> |
<a class="navig" href="<% this.href action="functionindex" %>">INDEX</a> |
<a class="navig" href="#A">A</a>|<a class="navig" href="#B">B</a>|<a class="navig" href="#C">C</a>|<a class="navig" href="#D">D</a>|<a class="navig" href="#E">E</a>|<a class="navig" href="#F">F</a>|<a class="navig" href="#G">G</a>|<a class="navig" href="#H">H</a>|<a class="navig" href="#I">I</a>|<a class="navig" href="#J">J</a>|<a class="navig" href="#K">K</a>|<a class="navig" href="#L">L</a>|<a class="navig" href="#M">M</a>|<a class="navig" href="#N">N</a>|<a class="navig" href="#O">O</a>|<a class="navig" href="#P">P</a>|<a class="navig" href="#Q">Q</a>|<a class="navig" href="#R">R</a>|<a class="navig" href="#S">S</a>|<a class="navig" href="#T">T</a>|<a class="navig" href="#U">U</a>|<a class="navig" href="#V">V</a>|<a class="navig" href="#W">W</a>|<a class="navig" href="#X">X</a>|<a class="navig" href="#Y">Y</a>|<a class="navig" href="#Z">Z</a>|
<table width="90%" border="0" cellspacing="1" cellpadding="5">
<% this.functions skin="asIndexItem"
separator="<tr><td class='mainbox'><img src='' width=0 height=0></td></tr>"
%>
</table>
<a class="navig" href="<% this.href action="summary"%>">SUMMARY</a> |
<a class="navig" href="<% this.href action="functionindex" %>">INDEX</a> |
<a class="navig" href="#A">A</a>|<a class="navig" href="#B">B</a>|<a class="navig" href="#C">C</a>|<a class="navig" href="#D">D</a>|<a class="navig" href="#E">E</a>|<a class="navig" href="#F">F</a>|<a class="navig" href="#G">G</a>|<a class="navig" href="#H">H</a>|<a class="navig" href="#I">I</a>|<a class="navig" href="#J">J</a>|<a class="navig" href="#K">K</a>|<a class="navig" href="#L">L</a>|<a class="navig" href="#M">M</a>|<a class="navig" href="#N">N</a>|<a class="navig" href="#O">O</a>|<a class="navig" href="#P">P</a>|<a class="navig" href="#Q">Q</a>|<a class="navig" href="#R">R</a>|<a class="navig" href="#S">S</a>|<a class="navig" href="#T">T</a>|<a class="navig" href="#U">U</a>|<a class="navig" href="#V">V</a>|<a class="navig" href="#W">W</a>|<a class="navig" href="#X">X</a>|<a class="navig" href="#Y">Y</a>|<a class="navig" href="#Z">Z</a>|

View file

@ -0,0 +1,97 @@
/**
* Get the prototype of any doc-object (either a prototype, a function or a tag)
*/
function getDocPrototype(obj) {
var tmp = obj;
while (tmp != null && tmp.getType() != this.PROTOTYPE) {
tmp = tmp.getParentElement();
}
return tmp;
}
/**
* Get a prototype of this docapplication, ie get on of the children of this object
*/
function getPrototype(name) {
return this.getChildElement("prototype_" + name);
}
/**
* Method used by Helma for URL composition.
*/
function href(action) {
var base = this.getParentElement().href() + "api/";
return action ? base + action : base;
}
function getDir(dir, obj) {
dir.mkdir();
if (obj.getType() == this.APPLICATION) {
return dir;
} else {
var protoObj = this.getDocPrototype(obj);
var dir = new File (dir, protoObj.getElementName());
dir.mkdir();
return dir;
}
}
function renderApi() {
var prefix = this.href("");
this.storePage(this, "main", "", "index.html");
this.storePage(this, "prototypes");
this.storePage(this, "summary");
this.storePage(this, "functionindex");
var ct = 4;
var arr = this.listChildren();
for (var i = 0; i < arr.length; i++) {
this.storePage(arr[i], "list", "../");
this.storePage(arr[i], "main", "../");
ct += 2;
var subarr = arr[i].listChildren();
for (var j = 0; j < subarr.length; j++) {
this.storePage(subarr[j], "main", "../", subarr[j].getElementName() + ".html");
ct += 1;
}
}
return ct;
}
function storePage(obj, action, backPath, filename) {
if (filename == null)
var filename = action + ".html";
var str = this.getPage(obj, action, backPath);
var appObj = this.getParentElement();
var dir = new File (appObj.getAppDir().getAbsolutePath(), ".docs");
dir = this.getDir(dir, obj);
var f = new File (dir, filename);
f.remove();
f.open();
f.write(str);
f.close();
app.log("wrote file " + f.getAbsolutePath());
}
function getPage(obj, action, backPath) {
backPath = (backPath == null) ? "" : backPath;
res.pushStringBuffer();
eval("obj." + action + "_action ();");
var str = res.popStringBuffer();
// get the baseURI out of the url and replace
// it with the given relative prefix
// (keep anchors in regex!)
var reg = new RegExp ("href=\"" + this.href("") + "([^\"#]+)([^\"]*)\"", "gim");
str = str.replace(reg, "href=\"" + backPath + "$1.html$2\"");
var reg = new RegExp ("src=\"" + this.href("") + "([^\"#]+)([^\"]*)\"", "gim");
str = str.replace(reg, "src=\"" + backPath + "$1.html$2\"");
// shorten links, so that function files can move up one directory
// in the hierarchy
var reg = new RegExp ("(prototype_[^/]+/[^/]+)/main.html", "gim");
str = str.replace(reg, "$1.html");
return str;
}

View file

@ -0,0 +1,3 @@
<tr><td class='headline'><a name="<% param.letter %>"><!-- --></a>
<big><% param.letter %></big>
</td></tr>

View file

@ -0,0 +1,106 @@
/**
* 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(param) {
return this.href((param && param.action) ? param.action : "main");
}
function comment_macro(param) {
return renderComment(this, param);
}
function content_macro(param) {
return this.getContent();
}
function tags_macro(param) {
return renderTags(this, param);
}
function location_macro(param) {
return renderLocation(this, param);
}
function link_macro(param) {
return renderLink(this, param);
}
//// END OF COPIED FUNCTIONS
function linkToManage_macro(param) {
if (res.data.rendering != true) {
return ('<a href="' + root.href("main") + '" target="_top">back to manage console</a>');
}
}
function headline_macro(param) {
res.write(this.getName());
}
function hrefRoot_macro(param) {
var obj = this.getChildElement("prototype_root");
if (obj == null) {
var obj = this.getChildElement("prototype_Root");
}
if (obj != null) {
var action = (param.action) ? param.action : "main";
return obj.href(action);
}
}
/**
* list all prototypes of this application
* @param skin name of skin to render on prototype
* @param separator
*/
function prototypes_macro(param) {
var skin = (param.skin) ? param.skin : "asPrototypeList";
var separator = (param.separator) ? param.separator : "";
var arr = this.listChildren();
for (var i = 0; i < arr.length; i++) {
arr[i].renderSkin(skin);
if (i < arr.length - 1)
res.write(separator);
}
}
/**
* list all methods of all prototypes, sort them alphabetically
* @param skin name of skin to render on each method
* @param skinSeparator name of skin to render as separator between each letters
*/
function functions_macro(param) {
var skinname = (param.skin) ? param.skin : "asListItem";
var skinIndexSeparator = (param.indexSeparator) ? param.indexSeparator : "indexSeparator";
var separator = (param.separator) ? param.separator : "";
var arr = this.listFunctions();
var lastLetter = "";
for (var i = 0; i < arr.length; i++) {
if (arr[i].getName().substring(0, 1) != lastLetter) {
lastLetter = arr[i].getName().substring(0, 1);
var tmp = new Object ();
tmp.letter = lastLetter.toUpperCase();
this.renderSkin(skinIndexSeparator, tmp);
}
arr[i].renderSkin(skinname);
if (i < arr.length - 1)
res.write(separator);
}
}

View file

@ -0,0 +1,10 @@
<% this.linkToManage suffix="<br/><br/>" %>
<big class="top">Application <a href="<% this.href action="summary" %>" target="main"><% this.name %></a></big><br><br>
<% this.prototypes %>

View file

@ -0,0 +1,29 @@
<table width="90%" border="0" cellspacing="1" cellpadding="5">
<tr>
<td class="headline">
<big class="top">Application <% this.headline %></tt></b></big><br>
</td>
</tr>
</table>
<a class="navig" href="<% this.href action="summary"%>">SUMMARY</a> |
<a class="navig" href="<% this.href action="functionindex" %>">INDEX</a> |
<% this.comment encoding="html" %>
<hr>
<table width="90%" border="0" cellspacing="1" cellpadding="5">
<% this.prototypes skin="asSummary"
separator="<tr><td class='mainbox'><img src='' width=0 height=0></td></tr>"
%>
</table>
<a class="navig" href="<% this.href action="summary"%>">SUMMARY</a> |
<a class="navig" href="<% this.href action="functionindex" %>">INDEX</a> |

View file

@ -0,0 +1,11 @@
function main_action() {
if (checkAddress() == false)
return;
if (checkAuth() == false)
return;
res.data.body = this.renderSkinAsString("main");
renderSkin("api");
}

View file

@ -0,0 +1,7 @@
<tr><td>
<% this.link handler="false" %>
- <% this.type %> in <% docprototype.name %>
<br/>
<% this.comment length="200" %>
</td></tr>

View file

@ -0,0 +1,5 @@
<tr><td>
<a href="<% this.href action="main" %>" target="main"><% this.link %></a><br/>
<% this.comment length="200" %>
</td></tr>

View file

@ -0,0 +1,8 @@
<tr><td>
<a href="<% this.href action="main" %>" target="main"><% this.link %></a><br/>
<% this.comment length="200" %>
<% this.skinparameters separator=", "%>
</td></tr>

View file

@ -0,0 +1,2 @@
<% this.link %><br>

View file

@ -0,0 +1 @@
<% this.link %>

View file

@ -0,0 +1,10 @@
/**
* Method used by Helma for URL composition.
*/
function href(action) {
var base = this.getParentElement().href()
+ this.getElementName() + "/";
return action ? base + action : base;
}

View file

@ -0,0 +1,150 @@
/**
* 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(param) {
return this.href((param && param.action) ? param.action : "main");
}
function comment_macro(param) {
return renderComment(this, param);
}
function content_macro(param) {
return this.getContent();
}
function tags_macro(param) {
return renderTags(this, param);
}
function location_macro(param) {
return renderLocation(this, param);
}
function link_macro(param) {
return renderLink(this, param);
}
//// END OF COPIED FUNCTIONS
function headline_macro(param) {
var p = this.getParentElement();
var handler = (p != null) ? p.getName() : "";
if (this.getType() == this.ACTION) {
res.write("/" + this.getName());
} else if (this.getType() == this.FUNCTION) {
if (handler != "" && handler != "global")
res.write(handler + ".");
res.write(this.getName() + "&nbsp;(");
var arr = this.listParameters();
for (var i = 0; i < arr.length; i++) {
res.write(arr[i]);
if (i < arr.length - 1) {
res.write(",&nbsp;");
}
}
res.write(")");
} else if (this.getType() == this.MACRO) {
res.write("&lt;%&nbsp;");
if (handler != "" && handler != "global")
res.write(handler + ".");
var name = this.getName();
if (name.indexOf("_macro") > -1)
name = name.substring(0, name.length - 6);
res.write(name);
res.write("&nbsp;%&gt;");
} else if (this.getType() == this.SKIN) {
if (handler != "" && handler != "global")
res.write(handler + "/");
res.write(this.getName());
res.write(".skin");
} else if (this.getType() == this.PROPERTIES) {
res.write(this.getName());
}
}
function skinparameters_macro(param) {
if (this.getType() == this.SKIN) {
this.parameters_macro(param);
}
}
function parameters_macro(param) {
var separator = (param.separator) ? param.separator : ", ";
var arr = this.listParameters();
for (var i = 0; i < arr.length; i++) {
res.write(arr[i]);
if (i < arr.length - 1)
res.write(separator);
}
}
function type_macro(param) {
return this.getTypeName();
}
/**
* macro returning nicely formatted sourcecode of this method.
* code is encoded, &gt% %&lt;-tags are colorcoded, line numbers are added
*/
function source_macro(param) {
var sourcecode = this.getContent();
if (param.as == "highlighted") {
sourcecode = encode(sourcecode);
// highlight macro tags
r = new RegExp("&lt;%", "gim");
sourcecode = sourcecode.replace(r, '<font color="#aa3300">&lt;%');
r = new RegExp("%&gt;", "gim");
sourcecode = sourcecode.replace(r, '%&gt;</font>');
// highlight js-comments
r = new RegExp("^([ \\t]*//.*)", "gm");
sourcecode = sourcecode.replace(r, '<font color="#33aa00">$1</font>');
// highlight quotation marks, but not for skins
if (this.getTypeName() != "Skin") {
r = new RegExp("(&quot;.*?&quot;)", "gm");
sourcecode = sourcecode.replace(r, '<font color="#9999aa">$1</font>');
r = new RegExp("(\'[\']*\')", "gm");
sourcecode = sourcecode.replace(r, '<font color="#9999aa">$1</font>');
}
// remove all CR and LF, just <br> remains
var r = new RegExp("[\\r\\n]", "gm");
sourcecode = sourcecode.replace(r, "");
var arr = sourcecode.split("<br />");
var line = this.getStartLine ? this.getStartLine() : 1;
for (var i = 0; i < arr.length; i++) {
res.write('<font color="#aaaaaa">' + (line++) + ':</font> ');
if (i < 99) {
res.write(' ');
}
if (i < 9) {
res.write(' ');
}
res.write(arr[i] + "\n");
}
} else {
res.write(sourcecode);
}
}

View file

@ -0,0 +1,34 @@
<table width="90%" border="0" cellspacing="1" cellpadding="5">
<tr>
<td class="headline">
<big><tt><% this.headline %></tt></big><br>
</td>
</tr>
<tr>
<td class="mainbox">
<% this.comment suffix="<br><br>" %>
<% this.skinparameters prefix="general parameters used in this skin:<ul><li><code>" separator="</code><li><code>" suffix="</code></ul><br>" %>
<ul>
<% this.tags type="param" skin="parameter" %>
<% this.tags type="return" skin="return" %>
<% this.tags type="author" skin="author" %>
<% this.tags type="see" skin="see" %>
<% this.tags type="deprecated" skin="deprecated" %>
<% this.tags type="overrides" skin="overrides" %>
</ul>
</td>
</tr>
</table>
<table width="90%" border="0" cellspacing="1" cellpadding="5">
<tr>
<td>Sourcecode in <% this.location %>:
<pre><% this.source as="highlighted" %></pre>
</td>
</tr>
</table>

View file

@ -0,0 +1,18 @@
function list_action() {
if (checkAddress() == false)
return;
if (checkAuth() == false)
return;
res.data.body = this.renderSkinAsString("list");
renderSkin("api");
}
function main_action() {
if (checkAddress() == false)
return;
if (checkAuth() == false)
return;
res.data.body = this.renderSkinAsString("main");
renderSkin("api");
}

View file

@ -0,0 +1 @@
extends Prototype <a href="<% this.href action="list" %>"><% this.name %></a>

View file

@ -0,0 +1,16 @@
<tr><td class='headline'><b>Inherited from prototype <% this.link %>:</b><br></td></tr>
<tr><td>
<% this.methods separator=", " filter="actions" skin="asParentListItem" prefix="<b>Actions: </b>" suffix="<br/>" %>
<% this.methods separator=", " filter="functions" skin="asParentListItem" prefix="<b>Functions: </b>" suffix="<br/>" %>
<% this.methods separator=", " filter="macros" skin="asParentListItem" prefix="<b>Macros: </b>" suffix="<br/>" %>
<% this.methods separator=", " filter="skins" skin="asParentListItem" prefix="<b>Skins: </b>" suffix="<br/>" %>
</td></tr>

View file

@ -0,0 +1,10 @@
<a href="<% this.href action="main" %>" onClick="parent.changePrototypeList(this);" target="main"><% this.name %></a>
<%
this.inheritance action="main" target="main"
onClick="parent.changePrototypeList(this);" hopobject="false"
prefix=" (extends " suffix=")"
%>
<br />

View file

@ -0,0 +1,4 @@
<tr><td>
<a href="<% this.href action="main" %>"><% this.name %></a><br/>
<% this.comment length="200" %>
</td></tr>

View file

@ -0,0 +1,30 @@
function translateType(filter) {
if (filter == "actions")
return Packages.helma.doc.DocElement.ACTION;
else if (filter == "functions")
return Packages.helma.doc.DocElement.FUNCTION;
else if (filter == "macros")
return Packages.helma.doc.DocElement.MACRO;
else if (filter == "skins")
return Packages.helma.doc.DocElement.SKIN;
else if (filter == "properties")
return Packages.helma.doc.DocElement.PROPERTIES;
else
return -1;
}
/**
* Get the application we're part of.
*/
function getApplication() {
return this.getParentElement();
}
/**
* Method used by Helma for URL composition.
*/
function href(action) {
var base = this.getParentElement().href()
+ this.getElementName() + "/";
return action ? base + action : base;
}

View file

@ -0,0 +1,10 @@
<big>Prototype <a href="<% this.href action="main" %>" target="main"><% this.name %></a></big><br/>
<% this.inheritance action="list" %>
<% this.inheritance deep="true" hopobject="true" action="main" target="main" onClick="parent.changePrototypeList(this);" separator=", " prefix="extends: " suffix="<br>" %><br>
<% this.methods filter="actions" skin="asListItem" prefix="<p><b>Actions:</b><br/>" suffix="</p>" %>
<% this.methods filter="functions" skin="asListItem" prefix="<p><b>Functions:</b><br/>" suffix="</p>" %>
<% this.methods filter="macros" skin="asListItem" prefix="<p><b>Macros:</b><br/>" suffix="</p>" %>
<% this.methods filter="skins" skin="asListItem" prefix="<p><b>Skins:</b><br/>" suffix="</p>" %>

View file

@ -0,0 +1,165 @@
/**
* 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(param) {
return this.href((param && param.action) ? param.action : "main");
}
function comment_macro(param) {
return renderComment(this, param);
}
function content_macro(param) {
return this.getContent();
}
function tags_macro(param) {
return renderTags(this, param);
}
function location_macro(param) {
return renderLocation(this, param);
}
function link_macro(param) {
return renderLink(this, param);
}
//// END OF COPIED FUNCTIONS
function headline_macro(param) {
res.write(this.getName());
}
/**
* macro formatting list of methods of this prototype
* @param filter actions | functions | macros | skins
* @param skin skin to apply to the docfunction object
* @param separator
* @param desc Description that is passed on to the called skin
*/
function methods_macro(param) {
var skinname = (param.skin) ? param.skin : "list";
var separator = (param.separator) ? param.separator : "";
var arr = this.listChildren();
var type = this.translateType(param.filter);
var sb = new java.lang.StringBuffer ();
for (var i = 0; i < arr.length; i++) {
if (arr[i].getType() == type) {
sb.append(arr[i].renderSkinAsString(skinname, param));
sb.append(separator);
}
}
var str = sb.toString();
if (str.length > 0)
return str.substring(0, str.length - separator.length);
else
return str;
}
function inheritance_macro(param) {
var action = param.action ? param.action : "main";
var target = param.target ? ('target="' + param.target + '" ') : '';
var obj = this.getParentPrototype();
if (obj != null) {
obj = this.inheritanceUtil(obj, param);
}
if (param.deep == "true") {
while (obj != null) {
obj = this.inheritanceUtil(obj, param);
}
}
}
function inheritanceUtil(obj, param) {
if (obj.getName() == "hopobject" && param.hopobject != "true")
return null;
var tmp = new Object ();
for (var i in param)
tmp[i] = param[i];
tmp.href = obj.href((param.action) ? param.action : "main");
delete tmp.hopobject;
delete tmp.action;
delete tmp.deep;
delete tmp.separator;
res.write(renderLinkTag(tmp));
res.write(obj.getName() + "</a>");
if (obj.getParentPrototype())
res.write(param.separator);
return obj.getParentPrototype();
}
/**
* loops through the parent prototypes and renders a skin on each
* if it has got any functions.
* @param skin
*/
function parentPrototype_macro(param) {
var skinname = (param.skin) ? param.skin : "asParentList";
var obj = this.getParentPrototype();
while (obj != null) {
if (obj.listChildren().length > 0) {
obj.renderSkin(skinname);
}
obj = obj.getParentPrototype();
}
}
/**
* macro rendering a skin depending on wheter this prototype has got
* type-properties or not.
* @param skin
*/
function typeProperties_macro(param) {
var props = this.getTypeProperties();
var iter = props.getResources();
while (iter.hasNext()) {
var tmp = this.renderTypePropertiesResource(iter.next(), props);
var skinname = (param.skinname) ? param.skinname : "typeproperties";
this.renderSkin(skinname, tmp);
}
}
function renderTypePropertiesResource(res, props) {
if (res.getContent() != "") {
var sb = new java.lang.StringBuffer ();
// map of all mappings....
var mappings = props.getMappings();
// parse type.properties linewise:
var arr = res.getContent().split("\n");
for (var i = 0; i < arr.length; i++) {
arr [i] = arr[i].trim();
// look up in mappings table if line matches:
for (var e = mappings.keys(); e.hasMoreElements();) {
var key = e.nextElement();
var reg = new RegExp ('^' + key + '\\s');
if (arr[i].match(reg)) {
// it matched, wrap line in a link to that prototype:
var docProtoObj = this.getApplication().getPrototype(mappings.getProperty(key));
if (docProtoObj != null) {
arr[i] = '<a href="' + docProtoObj.href("main") + '#typeproperties">' + arr[i] + '</a>';
}
}
}
sb.append(arr[i] + "\n");
}
var tmp = new Object ();
tmp.content = sb.toString();
tmp.source = res.getName();
return tmp;
}
}

View file

@ -0,0 +1,81 @@
<table width="90%" border="0" cellspacing="1" cellpadding="5">
<tr>
<td class="headline">
<big><tt>Prototype <% this.headline %></tt></big><br>
<% this.inheritance deep="true" hopobject="true" action="main" target="main" onClick="parent.changePrototypeList(this);" separator=", " prefix="extends: " suffix="<br>" %>
</td>
</tr>
</table>
<a class="navig" href="#actions">ACTIONS</a> |
<a class="navig" href="#functions">FUNCTIONS</a> |
<a class="navig" href="#macros">MACROS</a> |
<a class="navig" href="#skins">SKINS</a> |
<a class="navig" href="#typeproperties">TYPE.PROPERTIES</a>
<br/><br/>
<table width="90%" border="0" cellspacing="1" cellpadding="5">
<tr>
<td class="mainbox">
<% this.comment suffix="<br><br>" %>
<ul>
<% this.tags type="author" skin="author" %>
<% this.tags type="see" skin="see" %>
<% this.tags type="deprecated" skin="deprecated" %>
<% this.tags type="overrides" skin="overrides" %>
</ul>
</td>
</tr>
</table>
<table width="90%" border="0" cellspacing="1" cellpadding="3">
<% this.methods separator="<tr><td class='mainbox'><img src='' width=0 height=0></td></tr>"
filter="actions"
skin="asLargeListItem"
prefix="<tr><td class='headline'>Actions<a name='actions'><!-- --></a></td></tr>"
suffix="<tr><td height='8'>&nbsp;</td></tr>"
%>
<% this.methods separator="<tr><td class='mainbox'><img src='' width=0 height=0></td></tr>"
filter="functions"
skin="asLargeListItem"
prefix="<tr><td class='headline'>Functions<a name='functions'><!-- --></a></td></tr>"
suffix="<tr><td height='8'>&nbsp;</td></tr>"
%>
<% this.methods separator="<tr><td class='mainbox'><img src='' width=0 height=0></td></tr>"
filter="macros"
skin="asLargeListItem"
prefix="<tr><td class='headline'>Macros<a name='macros'><!-- --></a></td></tr>"
suffix="<tr><td height='8'>&nbsp;</td></tr>"
%>
<% this.methods separator="<tr><td class='mainbox'><img src='' width=0 height=0></td></tr>"
filter="skins"
skin="asLargeListItemSkin"
prefix="<tr><td class='headline'>Skins<a name='skins'><!-- --></a></td></tr>"
suffix="<tr><td height='8'>&nbsp;</td></tr>"
%>
<% this.methods separator="<tr><td class='mainbox'><img src='' width=0 height=0></td></tr>"
filter="properties"
skin="asLargeListItemSkin"
prefix="<tr><td class='headline'>type.properties<a name='typeproperties'><!-- --></a></td></tr>"
suffix="<tr><td height='8'>&nbsp;</td></tr>"
%>
<% this.parentPrototype skin="asParentList" %>
</table>
<br/><br/>
<!-- % this.typeProperties % -->

View file

@ -0,0 +1,9 @@
<a name='typeproperties'><!-- --></a>
<table width='90%' border='0' cellspacing='1' cellpadding='5'><tr>
<td class="headline">type.properties in <% param.source %></td>
</tr>
<tr>
<td class="mainbox"><pre><% param.content %></pre></td>
</tr>
</table>

View file

@ -0,0 +1,2 @@
<li><b>Author</b><br/>
<% this.text %>

View file

@ -0,0 +1,2 @@
<li><b>Deprecated</b><br/>
<% this.text %>

1
src/dist/apps/manage/DocTag/main.skin vendored Normal file
View file

@ -0,0 +1 @@
<li><% this.text %>

View file

@ -0,0 +1,3 @@
<li><b>Overrides</b><br/>
<% param.link %>

View file

@ -0,0 +1,2 @@
<li><b>Parameter</b> <code><% this.name %></code>:<br/>
<% this.text %>

View file

@ -0,0 +1,2 @@
<li><b>Returns</b><br>
<% this.text %>

2
src/dist/apps/manage/DocTag/see.skin vendored Normal file
View file

@ -0,0 +1,2 @@
<li><b>See also</b><br>
<% param.link %>

67
src/dist/apps/manage/Global/api.skin vendored Normal file
View file

@ -0,0 +1,67 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<html>
<head>
<title></title>
<style type="text/css">
body, p, td, th, li {
font-family: verdana, sans-serif;
font-size: 10pt;
}
big.top {
font-size: 18pt;
font-weight: bold;
}
big {
font-size: 13pt;
font-weight: bold;
}
a {
font-weight:bold;
color: #cc3333;
text-decoration:none;
}
a:hover {
text-decoration:underline;
}
.navig {
font-size: 9px;
text-decoration: none;
font-weight:normal;
}
li {
padding-bottom: 5px;
}
.mainbox {
border-color:#999999;
padding-top:5px;
padding-bottom:5px;
border-bottom-width:1px;
border-bottom-style:dotted;
}
.headline {
font-weight:bold;
background:#dfdfdf;
border-color:#999999;
padding-top:5px;
padding-bottom:5px;
}
</style>
</head>
<body>
<% response.body %>
</body>
</html>

View file

@ -0,0 +1,5 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<% response.head %>
<% response.body %>
</html>

262
src/dist/apps/manage/Global/functions.js vendored Normal file
View file

@ -0,0 +1,262 @@
/**
* scheduler function, runs global.appStat every minute
*/
function scheduler() {
appStat();
return 60000;
}
/**
* initializes app.data.stat storage on startup,
* creates app.data.addressFilter
*/
function onStart() {
app.data.addressFilter = createAddressFilter();
app.data.addressString = root.getProperty("allowadmin");
}
/**
* initializes addressFilter from app.properties,
* hostnames are converted, wildcards are only allowed in ip-addresses
* (so, no network-names, sorry)
*/
function createAddressFilter() {
var filter = new Packages.helma.util.InetAddressFilter();
var str = root.getProperty("allowadmin");
if (str != null && str != "") {
var arr = str.split(",");
for (var i in arr) {
str = new java.lang.String(arr[i]);
try {
filter.addAddress(str.trim());
} catch (a) {
try {
str = java.net.InetAddress.getByName(str.trim()).getHostAddress();
filter.addAddress(str);
} catch (b) {
app.log("error using address " + arr[i] + ": " + b);
}
}
}
} else {
app.log("no addresses allowed for app manage, all access will be denied");
}
return filter;
}
/**
* updates the stats in app.data.stat every 5 minutes
*/
function appStat() {
if (app.data.stat == null)
app.data.stat = new HopObject ();
if ((new Date() - 300000) < app.data.stat.lastRun)
return;
var arr = root.getApplications();
for (var i = 0; i < arr.length; i++) {
var tmp = app.data.stat[arr[i].getName()];
if (tmp == null) {
tmp = new HopObject();
tmp.lastTotalRequestCount = 0;
tmp.lastTotalErrorCount = 0;
}
tmp.requestCount = arr[i].getRequestCount() - tmp.lastTotalRequestCount;
tmp.lastTotalRequestCount = arr[i].getRequestCount();
tmp.errorCount = arr[i].getErrorCount() - tmp.lastTotalErrorCount;
tmp.lastTotalErrorCount = arr[i].getErrorCount();
app.data.stat[arr[i].getName()] = tmp;
}
app.data.stat.lastRun = new Date();
}
/**
* utility function to sort object-arrays by name
*/
function sortByName(a, b) {
if (a.name > b.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 appObj application object to check against (if adminUsername etc are set in app.properties)
*/
function checkAuth(appObj) {
if (res && res.data.noWeb == true) {
return true;
}
var ok = false;
// check against root
var adminAccess = root.getProperty("adminAccess");
if (adminAccess == null || adminAccess == "") {
res.redirect(root.href("makekey"));
}
var uname = req.username;
var pwd = req.password;
if (uname == null || uname == "" || pwd == null || pwd == "")
return forceAuth();
var md5key = Packages.helma.util.MD5Encoder.encode(uname + "-" + pwd);
if (md5key == adminAccess)
return true;
if (appObj != null && appObj.isActive()) {
// check against application
adminAccess = appObj.getProperty("adminAccess");
if (md5key == adminAccess)
return true;
}
return forceAuth();
}
/**
* check access to the manage-app by ip-addresses
*/
function checkAddress() {
if (res && res.data.noWeb == true) {
return true;
}
// if allowadmin value in server.properties has changed,
// re-construct the addressFilter
if (app.data.addressString != root.getProperty("allowadmin")) {
app.data.addressFilter = createAddressFilter();
app.data.addressString = root.getProperty("allowadmin");
}
if (!app.data.addressFilter.matches(java.net.InetAddress.getByName(req.data.http_remotehost))) {
app.log("denied request from " + req.data.http_remotehost);
// forceStealth seems a bit like overkill here.
// display a message that the ip address must be added to server.properties
res.write("Access from address " + req.data.http_remotehost + " denied.");
return false;
} else {
return true;
}
}
/**
* response is reset to 401 / authorization required
* @arg realm realm for http-auth
*/
function forceAuth(realm) {
res.reset();
res.status = 401;
res.realm = (realm != null) ? realm : "helma";
res.write("Authorization Required. The server could not verify that you are authorized to access the requested page.");
return false;
}
/**
* macro-utility: formatting property lists
*/
function formatProperties(props, par) {
if (props.size() == 0)
return "";
var e = props.keys();
var arr = new Array();
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(par.itemprefix + arr[i] + par.separator + props.getProperty(arr[i]) + par.itemsuffix);
}
}
/**
* 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);
age = age - days * 86400;
var hours = Math.floor(age / 3600);
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;
}
/**
* tries to make out if this server is running linux from java's system properties
*/
function isLinux() {
var str = java.lang.System.getProperty("os.name");
return (str != null && str.toLowerCase().indexOf("linux") != -1);
}

14
src/dist/apps/manage/Global/global.skin vendored Normal file
View file

@ -0,0 +1,14 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<% skin name="head" %>
<body bgcolor="white">
<table width="90%" border="0" cellspacing="1" cellpadding="5" bgcolor="#000000">
<tr>
<td width="30%" align="left" valign="top" bgcolor="#cccc99"><% skin name="navig" %></td>
<td width="70%" align="left" valign="top" bgcolor="#ffffff"><% response.body %></td>
</tr>
</table>
</body>
</html>

59
src/dist/apps/manage/Global/head.skin vendored Normal file
View file

@ -0,0 +1,59 @@
<head>
<title><% response.title %></title>
<style type="text/css">
<!--
body, p, td, th, li {
font-family: verdana, sans-serif;
font-size: 10pt;
}
.formEl {
border-color:#000000;
border-style:solid;
border-width:1px;
}
.list_apps {
border-color:#ffffff;
padding-top:5px;
padding-bottom:5px;
border-bottom-width:1px;
border-bottom-style:dotted;
}
.list_property {
border-color:#999999;
padding-top:5px;
padding-bottom:5px;
border-bottom-width:1px;
border-bottom-style:dotted;
}
.list_separator {
font-weight:bold;
background:#dfdfdf;
border-color:#999999;
padding-top:5px;
padding-bottom:5px;
border-bottom-width:1px;
border-bottom-style:dotted;
}
big {
font-size: 18pt;
font-weight: bold;
}
a {
font-weight:bold;
color: #cc3333;
text-decoration:none;
}
a:hover {
text-decoration:underline;
}
// -->
</style>
</head>

18
src/dist/apps/manage/Global/macros.js vendored Normal file
View file

@ -0,0 +1,18 @@
/**
* 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"));
}

30
src/dist/apps/manage/Global/navig.skin vendored Normal file
View file

@ -0,0 +1,30 @@
<p><a href="<% root.href action="main" %>"><img src="<% root.href action="image" %>" title="helma" border="0" width="174" height="35" align="baseline" style="border-width:3px;border-color:white;"></a>
</p>
<div class="list_apps">
<i><% root.appCount filter="active" singular=" app" plural=" apps"%> on
<a href="<% root.href action="main" %>"><% root.hostname %> (<% root.hostaddress %>)</a></i>
</div>
<% root.appList filter="active" %>
<p></p>
<div class="list_apps">
<i>disabled apps:</i>
</div>
<% root.appList filter="disabled" skin="navig_disabled" %>
<br/><br/>
<p>
Information on <a href="http://helma.org/">helma.org</a>:<br/>
<li><a href="http://helma.org/docs">reference</a><br/>
<li><a href="http://dev.helma.org/Mailing+Lists/">mailinglist</a><br/>
<li><a href="https://dev.helma.org/trac/helma/browser/helma/helma/trunk">svn</a><br/>
<li><a href="http://helma.org/download/">download</a><br/>
</p>
<p>
<li><a href="<% root.href action="makekey" %>">generate server password</a>
</p>

View file

@ -0,0 +1,20 @@
<body bgcolor="white">
<table width="500" border="0" cellspacing="0" cellpadding="5" bgcolor="#000000">
<tr>
<td width="500" align="left" valign="top" bgcolor="#ffffff">
<big>Generated username and password for helma's manager:</big><br>
<p>Please copy/paste this line into the server.properties file of your
helma installation.</p>
<pre><% param.propsString %></pre>
<p>After that proceed to <a href="<% root.href action="main" %>">the manage console</a>,
enter your credentials and you should be allowed in.</p>
</td></tr>
</table>
</body>

View file

@ -0,0 +1,28 @@
<body bgcolor="white">
<table width="500" border="0" cellspacing="0" cellpadding="5" bgcolor="#000000">
<tr>
<td width="500" align="left" valign="top" bgcolor="#ffffff">
<big>Username and password for helma's manager:</big><br>
<p>Please choose an username and password combination to access the
manage application of this server. They will be printed md5-encoded
in a format that you've got to copy/paste into the server.properties
file.</p>
<font color="red"><% param.msg %></font>
<form method="post">
<input class="formEl" name="username" size="25" value="<% param.username %>"> (username)<br>
<input class="formEl" type="password" name="password" size="25"> (password)<br>
<input class="formEl" type="submit" value="md5 encode"><br>
</form>
<p><b>Warning:</b> The used http-authorization transmits username and password
in an unsafe cleartext way. Therefore you're strongly discouraged to
use any given combination that is normally protected through SSH.</p>
</td></tr>
</table>
</body>

View file

@ -0,0 +1,153 @@
function renderLink(docEl, param) {
var text = "";
if (docEl.getType() == docEl.APPLICATION || docEl.getType() == docEl.PROTOTYPE) {
text = docEl.getName();
} else if (docEl.getType() == docEl.SKIN) {
text = docEl.getName() + ".skin";
} else if (docEl.getType() == docEl.MACRO) {
if (param.handler != "false" && docEl.getParentElement() && docEl.getParentElement().getName() != "global") {
text = docEl.getParentElement().getName() + ".";
}
var str = docEl.getName();
if (str.indexOf("_macro")) {
text += str.substring(0, str.length - 6);
}
} else if (docEl.getType() == docEl.FUNCTION) {
text = docEl.getName() + "(";
var arr = docEl.listParameters();
for (var i = 0; i < arr.length; i++) {
text += arr[i];
if (i < arr.length - 1)
text += ",&nbsp;";
}
text += ")";
} else {
text = docEl.getName();
}
param.href = docEl.href("main");
if (!param.target) {
param.target = "main";
}
return renderLinkTag(param) + text + '</a>';
}
function renderLinkTag(param) {
var sb = new java.lang.StringBuffer ();
sb.append('<a');
for (var i in param) {
sb.append(' ');
sb.append(i);
sb.append('="');
sb.append(param[i]);
sb.append('"');
}
sb.append('>');
return sb.toString();
}
/**
* renders the name of the location of a doc element.
*/
function renderLocation (docEl, param) {
return docEl.toString();
}
/**
* renders tag list.
* @param param.skin skin to render on found DocTags
* @param param.separator String printed between tags
* @param param.type type string (param|return|author|version|see) to filter tags.
*/
function renderTags(docEl, param) {
var skinname = (param.skin) ? param.skin : "main";
var type = param.type;
if (type == "params")
type = "param";
else if (type == "returns")
type = "return";
else if (type == "arg")
type = "param";
var str = "";
var arr = docEl.listTags();
for (var i = 0; i < arr.length; i++) {
if (arr[i].getType() == type) {
if (type == "see" || type == "overrides") {
param.link = renderReference(arr[i], docEl);
}
str += arr[i].renderSkinAsString(skinname, param);
str += (param.separator) ? param.separator : "";
}
}
return str;
}
/**
* renders a reference to functions in other prototypes, masks
* urls in a see tag
* (see- and overrides-tags)
* @param docTagObj
* @param docEl needed to be able to walk up to application object
*/
function renderReference(docTagObj, docEl) {
// prepare the text:
var text = docTagObj.getText();
text = new java.lang.String (text);
text = text.trim();
if (text.indexOf("http://") == 0) {
// an url is a simple job
return '<a href="' + text + '" target="_new">' + text + '</a>';
} else {
// make sure we only use the first item in the text so that unlinked comments
// can follow, store & split the that
var tok = new java.util.StringTokenizer (text);
var tmp = tok.nextToken();
text = " " + text.substring(tmp.length + 1);
var parts = tmp.split(".");
// try to find the application object
var obj = docEl;
while (obj != null) {
if (obj.getType() == Packages.helma.doc.DocElement.APPLICATION) {
var appObj = obj;
break;
}
obj = obj.getParentElement();
}
var protoObj = appObj.getChildElement("prototype_" + parts[0]);
if (protoObj == null) {
// prototype wasn't found, return the unlinked tag
return tmp + text;
}
if (parts.length == 1) {
// no function specified, return the linked prototype
return '<a href="' + protoObj.href("main") + '">' + format(tmp) + '</a>' + text;
}
// try to find a function object:
var arr = protoObj.listChildren();
for (var i = 0; i < arr.length; i++) {
if (arr[i].getName() == parts [1]) {
return '<a href="' + arr[i].href("main") + '">' + format(tmp) + '</a>' + text;
}
}
// function not found:
return tmp + text;
}
}
/**
* function rendering a comment.
* @param param.length comment is shortened to the given length.
* @returns string
*/
function renderComment(docEl, param) {
var str = docEl.getComment();
if (param.length) {
if (param.length < str.length) {
return str.substring(0, param.length) + " ...";
}
}
return str;
}

26
src/dist/apps/manage/README.md vendored Normal file
View file

@ -0,0 +1,26 @@
To get the manage application to work you need to
- add it to the `apps.properties` file with the following line:
```
manage
````
- use a Helma distribution version 1.5 or higher.
- add the following properties to the `server.properties` file:
```
allowAdmin = [comma-separated list of hosts or ip-addresses that
are allowed to access this application. wildcards
are only allowed in addresses, not in hostnames!]
adminAccess = <MD5-encoded credentials>
```
Creating the credentials can be done after you've got the application
up and running at this address:
```
http://<your-server-name>/manage/makekey
```

130
src/dist/apps/manage/Root/actions.js vendored Normal file
View file

@ -0,0 +1,130 @@
/**
* main action, show server-stats
* perform start, stop, restart and flush-action
*
*/
function main_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.clearCache();
res.redirect(appObj.href("main"));
}
}
// output only to root
if (checkAuth() == false) return;
res.data.title = "Helma Object Publisher - Serverinfo";
res.data.body = this.renderSkinAsString("main");
renderSkin("global");
}
/**
* return the helma object publisher logo, built into hop core
* to be independent of static html-paths
*/
function image_action() {
if (checkAddress() == false) return;
res.contentType = "image/gif";
res.writeBinary(Packages.helma.util.Logo.hop);
}
function makekey_action() {
if (checkAddress() == false)
return;
var obj = new Object();
obj.msg = "";
if (req.data.username != null && req.data.password != null) {
// we have input from webform
if (req.data.username == "")
obj.msg += "username can't be left empty!<br>";
if (req.data.password == "")
obj.msg += "password can't be left empty!<br>";
if (obj.msg != "") {
obj.username = req.data.username;
res.reset();
res.data.body = renderSkinAsString("pwdform", obj);
} else {
// render the md5-string:
obj.propsString = "adminAccess=" + Packages.helma.util.MD5Encoder.encode(req.data.username + "-" + req.data.password) + "<br>\n";
res.data.body = renderSkinAsString("pwdfeedback", obj);
}
} else {
// no input from webform, so print it
res.data.body = renderSkinAsString("pwdform", obj);
}
res.data.title = "username & password on " + root.hostname_macro();
res.data.head = renderSkinAsString("head");
renderSkin("basic");
}
/**
* prints server-stats for mrtg-tool.
* doesn't check username or password, so that we don't have
* to write them cleartext in a mrtg-configfile but checks the
* remote address.
*/
function mrtg_action() {
if (checkAddress() == false)
return;
if (req.data.action == "memory") {
res.write(this.jvmTotalMemory_macro() + "\n");
res.write(this.jvmFreeMemory_macro() + "\n");
res.write("0\n0\n");
} else if (req.data.action == "netstat" && isLinux()) {
var str = (new File("/proc/net/tcp")).readAll();
var arr = str.split("\n");
res.write(arr.length - 2 + "\n");
res.write("0\n0\n0\n");
} else if (req.data.action == "loadavg" && isLinux()) {
// load average of last 5 minutes:
var str = (new File("/proc/loadavg")).readAll();
var arr = str.split(" ");
res.write(arr[1] * 100 + "\n");
res.write("0\n0\n0\n");
} else {
res.write("0\n0\n0\n0\n");
}
}

76
src/dist/apps/manage/Root/functions.js vendored Normal file
View file

@ -0,0 +1,76 @@
/**
* renders the api of a given application. used from commandline.
*/
function renderApi(appName) {
// supress security checks when accessing actions
res.data.noWeb = true;
// start the application
this.startApplication(appName);
var appObj = this.getApp(appName);
var docApp = appObj.getChildElement("api");
// now render the api
var ct = docApp.renderApi();
writeln("rendered " + ct + " files");
// cleanup
this.stopApplication(appName);
}
/**
* lists all applications in appdir.
* for active apps use this.getApplications() = helma.main.Server.getApplications()
*/
function getAllApplications() {
var appsDir = this.getAppsHome();
var dir = appsDir.listFiles();
var arr = new Array();
var seen = {};
// first check apps directory for apps directories
if (dir) {
for (var i = 0; i < dir.length; i++) {
if (dir[i].isDirectory() && dir[i].name.toLowerCase() != "cvs") {
arr[arr.length] = this.getApp(dir[i].name);
seen[dir[i].name] = true;
}
}
}
// then check entries in apps.properties for apps not currently running
var props = wrapJavaMap(root.getAppsProperties(null));
for (var i in props) {
if (i.indexOf(".") < 0 && !seen[i] && !root.getApplication(i)) {
arr[arr.length] = this.getApp(i);
}
}
return arr;
}
/**
* get application by name, constructs an hopobject of the prototype application
* if the app is not running (and therefore can't be access through
* helma.main.ApplicationManager).
* ATTENTION: javascript should not overwrite helma.main.Server.getApplication() which
* retrieves active applications.
* @arg name of application
*/
function getApp(name) {
if (name == null || name == "")
return null;
var appObj = this.getApplication(name);
if (appObj == null)
appObj = new Application(name);
return appObj;
}
/**
* Method used by Helma path resolution.
*/
function getChildElement(name) {
return this.getApp(name);
}

284
src/dist/apps/manage/Root/macros.js vendored Normal file
View file

@ -0,0 +1,284 @@
/**
* 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 total number of sessions on this server
* @see global.formatCount
*/
function countSessions_macro(par) {
var arr = this.getApplications();
var sum = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i].getName() != app.__app__.getName()) {
sum += arr[i].sessions.size();
}
}
return sum + formatCount(sum, par);
}
/**
* macro returning the number of requests during the last 5 minutes
* @see global.formatCount
*/
function requestCount_macro(par) {
if (app.data.stat == null) {
return;
}
var arr = this.getApplications();
var sum = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i].getName() != app.__app__.getName()) { // don't include manage app
var obj = app.data.stat[arr[i].name];
if (obj != null) {
sum += obj.requestCount;
}
}
}
return sum + formatCount(sum, par);
}
/**
* macro returning the number of errors during the last 5 minutes
* @see global.formatCount
*/
function errorCount_macro(par) {
if (app.data.stat == null) {
return;
}
var arr = this.getApplications();
var sum = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i].getName() != app.__app__.getName()) { // don't include manage app
var obj = app.data.stat[arr[i].name];
if (obj != null) {
sum += obj.errorCount;
}
}
}
return sum + formatCount(sum, par);
}
function extensions_macro(par) {
var vec = this.getExtensions();
var str = "";
for (var i = 0; i < vec.size(); i++) {
str += vec.elementAt(i).getClass().getName();
if (i != (vec.size() - 1)) {
str += (par && par.separator) ? par.separator : ", ";
}
}
return (str == "") ? null : str;
}
/**
* Macro returning hostname of this machine
*/
function hostname_macro(par) {
return java.net.InetAddress.getLocalHost().getHostName()
}
/**
* Macro returning address of this machine
*/
function hostaddress_macro(par) {
return java.net.InetAddress.getLocalHost().getHostAddress()
}
/**
* Macro returning the number of running applications,
* the manage application being excluded.
*/
function appCount_macro(par) {
if (par && par.filter == "active") {
var ct = root.getApplications().length - 1;
} else if (par && par.filter == "disabled") {
var ct = root.getAllApplications().length - root.getApplications().length;
} else {
var ct = root.getAllApplications().length - 1;
}
return ct + formatCount(ct, par);
}
/**
* Macro that lists all running applications,
* the manage application being excluded (-1).
* @param skin skin of application that will be used.
*/
function appList_macro(par) {
var skin = (par && par.skin) ? par.skin : "navig_active";
var apps = new Array();
if (par && par.filter == "active") {
var arr = root.getApplications();
for (var i = 0; i < arr.length; i++) {
apps[apps.length] = arr[i];
}
} else if (par && par.filter == "disabled") {
var arr = root.getAllApplications();
for (var i in arr) {
if (arr[i].isActive() == false) {
apps[apps.length] = arr[i];
}
}
} else {
var apps = root.getAllApplications();
}
apps = apps.sort(sortByName);
var html = "";
var param = new Object();
for (var n in apps) {
var a = apps[n];
if (apps[n].name == app.__app__.getName())
continue;
var item = a.renderSkinAsString(skin);
html += item;
}
return(html);
}
/**
* Macro that returns the server's uptime nicely formatted
*/
function uptime_macro() {
return formatAge((java.lang.System.currentTimeMillis() - this.starttime) / 1000);
}
/**
* Macro that returns the server's version string
*/
function version_macro() {
return this.version;
}
/**
* Macro that returns the home directory of the hop installation
*/
function home_macro() {
return this.getHopHome().toString();
}
/**
* Macro that returns the free memory in the java virtual machine
* @param format if "hr", value will be printed human readable
*/
function jvmFreeMemory_macro(param) {
var m = java.lang.Runtime.getRuntime().freeMemory();
return (param && param.hr) ? formatBytes(m) : m;
}
/**
* Macro that returns the total memory available to the java virtual machine
* @param format if "hr", value will be printed human readable
*/
function jvmTotalMemory_macro(param) {
var m = java.lang.Runtime.getRuntime().totalMemory();
return (param && param.hr) ? formatBytes(m) : m;
}
/**
* Macro that returns the used memory in the java virtual machine
* @param format if "hr", value will be printed human readable
*/
function jvmUsedMemory_macro(param) {
var m = java.lang.Runtime.getRuntime().totalMemory() - java.lang.Runtime.getRuntime().freeMemory();
return (param && param.hr) ? formatBytes(m) : m;
}
/**
* Macro that returns the version and type of the java virtual machine
*/
function jvm_macro() {
return java.lang.System.getProperty("java.version") + " " + java.lang.System.getProperty("java.vendor");
}
/**
* Macro that returns the home directory of the java virtual machine
*/
function jvmHome_macro() {
return java.lang.System.getProperty("java.home");
}
/**
* Macro that greps all jar-files from the class path variable and lists them.
* @param separator string that is printed between the items
*/
function jvmJars_macro(par) {
var separator = (par && par.separator ) ? par.separator : ", ";
var str = java.lang.System.getProperty("java.class.path");
var arr = str.split(".jar");
for (var i in arr) {
var str = arr[i];
var pos = ( str.lastIndexOf('\\') > 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() + ")";
}

111
src/dist/apps/manage/Root/main.skin vendored Normal file
View file

@ -0,0 +1,111 @@
<big><% this.hostname %> (<% this.hostaddress %>)</big><br/><br/>
<table border="0" cellspacing="0" cellpadding="3">
<tr>
<td class="list_separator" colspan="3">helma</td>
</tr>
<tr>
<td class="list_property">uptime:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.uptime %></td>
</tr>
<tr>
<td class="list_property">version:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.version %></td>
</tr>
<tr>
<td class="list_property">homedir:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.home %></td>
</tr>
<tr>
<td class="list_property" valign="top">total active sessions:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.countSessions default="&nbsp;" %></td>
</tr>
<tr>
<td class="list_property" nowrap valign="top">total requests / 5 min:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.requestCount default="&nbsp;" %></td>
</tr>
<tr>
<td class="list_property" norwrap valign="top">total errors / 5 min:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.errorCount default="&nbsp;" %></td>
</tr>
<tr>
<td class="list_property" valign="top">loaded extensions:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.extensions default="&nbsp;" %></td>
</tr>
<tr>
<td class="list_separator" colspan="3">jre</td>
</tr>
<tr>
<td class="list_property">free memory:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.jvmFreeMemory hr="true" %></td>
</tr>
<tr>
<td class="list_property">used memory:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.jvmUsedMemory hr="true" %></td>
</tr>
<tr>
<td class="list_property">total memory:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.jvmTotalMemory hr="true" %></td>
</tr>
<tr>
<td class="list_property">java:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.jvm %></td>
</tr>
<tr>
<td class="list_property">javahome:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.jvmHome %></td>
</tr>
<tr>
<td class="list_property">os:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.os %></td>
</tr>
<tr>
<td class="list_property">localtime:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% now %></td>
</tr>
<tr>
<td class="list_property" valign="top">timezone:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.timezone %></td>
</tr>
<tr>
<td class="list_property" valign="top">loaded Jars:</td>
<td class="list_property" width="5">&nbsp;</td>
<td class="list_property" align="left"><% this.jvmJars %></td>
</tr>
<tr>
<td class="list_separator" colspan="3">server.properties</td>
</tr>
<% this.properties itemprefix='<tr><td class="list_property">' separator='</td><td class="list_property" width="5">&nbsp;</td><td class="list_property" align="left">' itemsuffix='</td></tr>' %>
</table>

12
src/dist/apps/manage/app.properties vendored Normal file
View file

@ -0,0 +1,12 @@
# Set baseURI for application generated URLs, if necessary.
# baseURI = /manage
# A short description of what this application is about:
_description = Helma's server management console. Start applications, introspection etc.
# use higher request timeout because rendering the apidocs
# might take more than one minute on a slow computer
requestTimeout = 300
# run scheduler function each minute
cron.scheduler.function = scheduler

27
src/dist/apps/manage/class.properties vendored Normal file
View file

@ -0,0 +1,27 @@
#
# define the root class of this application
#
root = helma.main.Server
#
# root.factory is used to retrieve the root class of the application
# when the instance has already been created when the application comes up.
# this is true for the helma server that is scripted here.
#
root.factory.class = helma.main.Server
root.factory.method = getServer
#
# Map Java classes to the prototype used to script them
# and, yes, map the root class again.
#
helma.main.Server = Root
helma.framework.core.Application = Application
helma.doc.DocApplication = DocApplication
helma.doc.DocPrototype = DocPrototype
helma.doc.DocFunction = DocFunction
helma.doc.DocProperties = DocFunction
helma.doc.DocSkin = DocFunction
helma.doc.DocTag = DocTag

10
src/dist/apps/test/README.md vendored Normal file
View file

@ -0,0 +1,10 @@
To run the tests, add something like this to your apps.properties file:
test
test.appdir = apps/test/code
test.repository.0 = apps/test/code
test.repository.1 = modules/jala/util/Test/code
And you need to have a JDBC driver for your database in lib/ext,
as well as create the database schema provided in one of the
db-<product>.sql files.

View file

@ -0,0 +1,33 @@
function onStart() {
root.date = new Date();
root.string = "root";
}
function hello_macro(param) {
return "hello";
}
function echo_macro(param, arg) {
return arg || param.what;
}
function isDate_filter(arg) {
return arg instanceof Date;
}
function isRootDate_filter(arg) {
return (arg instanceof Date) &&
arg.getTime() == root.date.getTime();
}
function isResponseDate_filter(arg) {
return (arg instanceof Date) && arg == res.data.date;
}
function makeLongString() {
var b = new java.lang.StringBuffer();
for (var i = 1; i <= 10000; i++) {
b.append(i.toString()).append(" ");
}
return b.toString();
}

View file

@ -0,0 +1 @@
mainskin<% #subskin1 %>subskin1<% #subskin2 %>subskin2<% #end %>

View file

@ -0,0 +1,40 @@
_db = dbcTest
_table = tb_organisation
_id = org_id
_parent = root.organisations
persons = collection(Person)
persons.local = org_id
persons.foreign = person_org_id
persons.accessname = person_name
persons.order = person_name
range = collection(Person)
range.local = org_id
range.foreign = person_org_id
range.accessname = person_name
range.order = person_name
range.offset = 100
range.maxsize = 100
generic = collection(Person)
generic.local.1 = $prototype
generic.foreign.1 = person_generic_prototype
generic.local.2 = $id
generic.foreign.2 = person_generic_id
generic.order = person_name
groupedGeneric = collection(Person)
groupedGeneric.local.1 = $prototype
groupedGeneric.foreign.1 = person_generic_prototype
groupedGeneric.local.2 = $id
groupedGeneric.foreign.2 = person_generic_id
groupedGeneric.group = person_name
groupedGeneric.group.order = person_name
name = org_name
country = org_country
someMountpoint = mountpoint(SomeMountpoint)

View file

@ -0,0 +1,17 @@
_db = dbcTest
_table = tb_person
_id = person_id
_parent = organisation.persons, root.persons
name = person_name
height = person_height
dateOfBirth = person_dateofbirth
organisation = object(Organisation)
organisation.local = person_org_id
organisation.foreign = org_id
genericPrototype = person_generic_prototype
genericId = person_generic_id

35
src/dist/apps/test/code/Root/root.js vendored Normal file
View file

@ -0,0 +1,35 @@
function main_action() {
res.redirect(root.href("jala.test"));
}
function hello_action() {
res.contentType = "text/plain";
res.write("Hello");
}
function throwerror_action() {
throw Error();
}
function notfound_action() {
res.write("Not found");
}
function redirect_action() {
res.redirect(this.href("hello"));
}
function error_action() {
res.write("Error");
}
function long_action() {
res.write(makeLongString());
}
function macro_macro(param) {
// change suffix
if (param.suffix) param.suffix = ".";
return this.string;
}

View file

@ -0,0 +1,16 @@
date = date
string = string
organisations = collection(Organisation)
organisations.accessname = org_name
organisationsByCountry = collection(Organisation)
organisationsByCountry.group = org_country
organisationsByCountry.group.prototype = Country
organisationsByCountry.group.order = org_country desc
organisationsByCountry.order = org_name desc
persons = collection(Person)
someMountpoint = mountpoint(SomeMountpoint)

View file

@ -0,0 +1,3 @@
baseUri = http://localhost:8080/test/
# hard-code cache size to default value to make sure there's some cache rotation
cacheSize = 500

15
src/dist/apps/test/code/db.properties vendored Normal file
View file

@ -0,0 +1,15 @@
#MySQL
dbcTest.url = jdbc:mysql://localhost/helmaTest
dbcTest.driver = com.mysql.jdbc.Driver
dbcTest.user = helma
dbcTest.password = secret
# Oracle
# dbcTest.url = jdbc:oracle:thin:@localhost:1521:XE
# dbcTest.driver = oracle.jdbc.driver.OracleDriver
# PostgreSQL
# dbcTest.url = jdbc:postgresql:helmaTest
# dbcTest.driver = org.postgresql.Driver

26
src/dist/apps/test/db-mysql.sql vendored Normal file
View file

@ -0,0 +1,26 @@
CREATE DATABASE IF NOT EXISTS helmaTest;
USE helmaTest;
GRANT ALL ON helmaTest.* TO helma@localhost IDENTIFIED BY 'secret';
DROP TABLE IF EXISTS tb_person;
DROP TABLE IF EXISTS tb_organisation;
CREATE TABLE tb_person (
person_id MEDIUMINT(10) NOT NULL,
person_name TINYTEXT,
person_height TINYINT unsigned,
person_dateofbirth DATETIME,
person_org_id MEDIUMINT(10) unsigned,
person_generic_prototype VARCHAR(30),
person_generic_id MEDIUMINT(10) unsigned,
PRIMARY KEY (person_id)
);
CREATE TABLE tb_organisation (
org_id MEDIUMINT(10) unsigned NOT NULL,
org_name TINYTEXT,
org_country TINYTEXT,
PRIMARY KEY (org_id)
);

15
src/dist/apps/test/db-oracle.sql vendored Normal file
View file

@ -0,0 +1,15 @@
CREATE TABLE tb_person (
person_id NUMBER(10) NOT NULL,
person_name VARCHAR2(255),
person_height NUMBER(10),
person_dateofbirth DATE,
person_org_id NUMBER(10),
PRIMARY KEY (person_id)
);
CREATE TABLE tb_organisation (
org_id NUMBER(10) NOT NULL,
org_name VARCHAR2(255),
org_country VARCHAR2(255),
PRIMARY KEY (org_id)
);

20
src/dist/apps/test/db-postgresql.sql vendored Normal file
View file

@ -0,0 +1,20 @@
CREATE TABLE tb_person (
person_id INTEGER NOT NULL,
person_name VARCHAR(100),
person_height INTEGER,
person_dateofbirth TIMESTAMP,
person_org_id INTEGER,
PRIMARY KEY (person_id)
);
CREATE TABLE tb_organisation (
org_id INTEGER NOT NULL,
org_name VARCHAR(100),
org_country VARCHAR(100),
PRIMARY KEY (org_id)
);
CREATE USER helma WITH PASSWORD 'secret';
GRANT insert, delete, select, update ON tb_person, tb_organisation TO helma;

View file

@ -0,0 +1,148 @@
tests = [
"testEquality",
"testSimpleMapping",
"testSimpleCollection",
"testObjectReference",
"testCollectionForReference"
];
function setup() {
}
function testEquality() {
var person = new Person();
root.persons.add(person);
res.commit();
var id = person._id;
app.clearCache();
var person2 = root.persons.get(id);
assertNotNull(person2);
assertTrue(person !== person2);
assertTrue(person._id === person2._id);
assertTrue(person == person2);
person.remove();
}
function testSimpleMapping() {
var data = {
name: "Oliver Stone",
dateOfBirth: new Date(1946, 8, 15, 6, 0, 0),
height: 182
};
var person = new Person();
person.name = data.name;
person.dateOfBirth = data.dateOfBirth;
person.height = data.height;
root.persons.add(person);
var personId = person._id;
res.commit(); // Commit Transaction
app.clearCache(); // Clear cache so that object is refetched
var person = Person.getById(personId);
assertNotNull(person);
assertEqual(person._prototype, "Person");
assertEqual(person._id, personId);
assertEqual(person.name, data.name);
assertEqual(person.height, data.height);
assertEqual(person.dateOfBirth.valueOf(), data.dateOfBirth.valueOf());
res.commit();
person.remove();
}
function testSimpleCollection() {
var data = {
name: "Helma"
};
var orgCount = root.organisations.count();
var org = new Organisation();
org.name = data.name;
root.organisations.add(org);
var orgId = org._id;
assertEqual(orgCount + 1, root.organisations.count());
assertNotEqual(root.organisations.indexOf(org), -1);
// fetch Object via position
assertEqual(root.organisations.get(root.organisations.indexOf(org)), org);
// fetch Object via accessname
assertEqual(root.organisations.get(data.name), org);
// fetch Object via id
assertEqual(root.organisations.getById(orgId), org);
// test list
assertEqual(root.organisations.count(), root.organisations.list().length);
org.remove();
assertEqual(orgCount, root.organisations.count());
assertEqual(root.organisations.indexOf(org), -1);
assertNull(root.organisations.get(data.name));
assertNull(root.organisations.getById(orgId));
}
function testObjectReference() {
var org = new Organisation();
org.name = "Helma";
root.organisations.add(org);
var orgId = org._id;
var person = new Person();
person.name = "Hannes";
person.organisation = org;
root.persons.add(person);
var personId = person._id;
res.commit(); // Commit Transaction
app.clearCache(); // Clear cache so that object is refetched
var org = Organisation.getById(orgId);
var person = Person.getById(personId);
assertEqual(person.organisation, org);
org.remove();
res.commit(); // Commit Transaction
assertNull(person.organisation);
person.remove();
}
function testCollectionForReference() {
var org = new Organisation();
org.name = "Helma";
root.organisations.add(org);
var orgId = org._id;
var personCount = org.persons.count();
var person = new Person();
person.name = "Hannes";
person.organisation = org;
root.persons.add(person);
org.persons.add(person);
assertEqual(personCount + 1, org.persons.count());
assertNotEqual(org.persons.indexOf(person), -1);
org.persons.removeChild(person);
person.remove();
assertEqual(personCount, org.persons.count());
assertEqual(org.persons.indexOf(person), -1);
org.remove();
}
function cleanup() {
}

View file

@ -0,0 +1,183 @@
tests = [
"testSize",
"testMaxSize",
"testAddSmall",
"testAddLarge",
"testRemoveSmall",
"testRemoveLarge",
"testUpdateSmall",
"testUpdateLarge",
"testListSmall",
"testListLarge",
"testOrderLarge",
"testOrderSmall"
];
var helma, ikea;
var small = 3, large = 1234;
function setup() {
ikea = makeOrg('Ikea', large);
helma = makeOrg('Helma', small);
}
function testSize() {
assertEqual(ikea.persons.size(), large);
assertEqual(helma.persons.size(), small);
}
function testMaxSize() {
assertEqual(ikea.range.size(), 100);
assertEqual(helma.range.size(), 0);
var person = ikea.range.get("Person Ikea 0150");
assertNotNull(person);
assertEqual(person, ikea.range.get(50));
assertEqual(person, ikea.persons.get(150));
assertEqual(50, ikea.range.indexOf(person));
assertEqual(150, ikea.persons.indexOf(person));
}
function testAddSmall() {
testAdd(helma, small);
}
function testAddLarge() {
testAdd(ikea, large);
}
// test directly adding to a collection
function testAdd(org, size) {
var person = new Person();
person.name = "TestPerson";
org.persons.add(person);
assertEqual(org.persons.size(), size + 1);
assertEqual(org.persons.indexOf(person), size);
assertEqual(org.persons.contains(person), size);
assertEqual(person.href(), org.persons.href() + "TestPerson/");
// make sure the add has set the back-reference on the person object.
// note that === comparison will return false if the
// collection size exceeds the cache size.
assertTrue(person.organisation == org);
}
function testRemoveSmall() {
testRemove(helma, small);
}
function testRemoveLarge() {
testRemove(ikea, large);
}
// test directly removing from a collection
function testRemove(org, size) {
var person = org.persons.get(org.persons.size() - 1);
person.remove();
assertEqual(org.persons.size(), size);
assertEqual(org.persons.indexOf(person), -1);
assertEqual(org.persons.contains(person), -1);
}
function testUpdateSmall() {
testUpdate(helma, small);
}
function testUpdateLarge() {
testUpdate(ikea, large);
}
// test indirectly adding to and removing form a collection
function testUpdate(org, size) {
var person = new Person();
person.name = "TestPerson";
person.organisation = org;
person.persist();
res.commit();
assertEqual(org.persons.size(), size + 1);
org.persons.prefetchChildren();
assertEqual(org.persons.indexOf(person), size);
assertEqual(org.persons.contains(person), size);
assertEqual(person.href(), org.persons.href() + "TestPerson/");
person.remove();
res.commit();
assertEqual(org.persons.size(), size);
assertEqual(org.persons.indexOf(person), -1);
assertEqual(org.persons.contains(person), -1);
}
function testListSmall() {
testList(helma, small);
}
function testListLarge() {
testList(ikea, large);
}
function testList(org, size) {
function iterate(list, start, length) {
assertEqual(list.length, length);
for (var i = 0; i < length; i++) {
assertEqual(list[i].name, "Person " + org.name + (start + i).format(" 0000"));
}
}
iterate(org.persons.list(), 0, size);
org.persons.invalidate();
iterate(org.persons.list(), 0, size);
org.persons.invalidate();
iterate(org.persons.list(1, size - 2), 1, size - 2);
}
function testOrderLarge() {
testOrder(ikea, ikea.persons.size() - 2);
testOrder(ikea, Math.floor(ikea.persons.size() / 2));
testOrder(ikea, 2);
}
function testOrderSmall() {
testOrder(helma, helma.persons.size() - 1);
testOrder(helma, 1);
testOrder(helma, 0);
}
function testOrder(org, pos) {
var person = new Person();
person.name = "Person " + org.name + pos.format(" 0000") + "B";
person.organisation = org;
root.persons.add(person);
res.commit();
assertEqual(pos + 1, org.persons.indexOf(person));
}
function cleanup() {
var persons = root.persons.list();
for each (var person in persons) {
person.remove();
}
ikea.remove();
helma.remove();
}
function makeOrg(name, size) {
var org = new Organisation();
org.name = name;
root.organisations.add(org);
for (var i = 0; i < size; i++) {
var person = new Person();
person.name = "Person " + name + i.format(" 0000");
person.organisation = org;
root.persons.add(person);
}
res.commit();
return org;
}
// debugging helpers
function dumpDataChange(message) {
res.debug(message + ": ");
dumpDataChangeFor("Person");
dumpDataChangeFor("Organisation");
}
function dumpDataChangeFor(name) {
res.debug(name + ": " + app.__app__.getDbMapping(name).getLastDataChange());
}

View file

@ -0,0 +1,93 @@
tests = [
'testSize',
'testContent',
'testGroupContent',
'testRemove',
'testAdd'
];
var org;
var size = 16;
function setup() {
org = new Organisation();
org.name = "GenericOrg";
var i = 0, person;
function addPerson(collection) {
person = new Person();
person.name = "GenericPerson " + i.format("00");
collection.add(person);
i++;
}
// add first half to both collections of transient parent ...
while (i < 4)
addPerson(org.generic);
while (i < 8)
addPerson(org.groupedGeneric);
root.organisations.add(org);
// ... second half to both collections of persistent parent.
while (i < 12)
addPerson(org.generic);
while (i < size)
addPerson(org.groupedGeneric);
res.commit();
}
function testSize() {
assertEqual(org.generic.size(), size);
org.invalidate();
assertEqual(org.generic.size(), size);
}
function testContent() {
var list = org.generic.list();
assertEqual(list.length, size);
for (var i = 0; i < list.length; i++) {
assertEqual(list[i].name, "GenericPerson " + i.format("00"));
}
}
function testGroupContent() {
var list = org.groupedGeneric.list();
assertEqual(list.length, size);
for (var i = 0; i < list.length; i++) {
assertEqual(list[i].groupname, "GenericPerson " + i.format("00"));
assertEqual(list[i].size(), 1);
assertEqual(list[i].get(0).name, "GenericPerson " + i.format("00"));
}
}
function testRemove() {
var person = org.generic.get(size/2);
org.generic.removeChild(person);
assertEqual(org.generic.size(), size - 1);
res.rollback();
// note: removeChild does not remove the node, nor does it
// unset the constraints between parent and child, so after a rollback
// the object is back in place. While this behaviour is disputable,
// until this is so we test for it.
assertEqual(org.generic.size(), size);
}
function testAdd() {
var person = new Person();
org.generic.add(person);
assertEqual(org.generic.size(), size + 1);
assertEqual(org.groupedGeneric.size(), size);
res.commit();
// note: even after commit the grouped collection must not grow
// since we added a person without a name
assertEqual(org.generic.size(), size + 1);
assertEqual(org.groupedGeneric.size(), size);
}
function cleanup() {
var persons = org.generic.list();
for each (var person in persons) {
person.remove();
}
org.remove();
}

View file

@ -0,0 +1,149 @@
tests = [
"testGroupByAddRemoveCommit",
"testGroupByAddRemoveNoCommit",
"testGroupOrder",
"testGroupTransient"
];
// todo: run with different sizes
var size = 1234;
function setup() {
for (var i = 0; i < size; i++) {
var org = new Organisation();
org.name = "Organisation " + i;
org.country = "CH" + i.format("0000");
// add to different collections
if (i % 2 == 0)
root.organisations.add(org);
else
root.organisationsByCountry.add(org);
}
res.commit();
}
function testGroupByAddRemoveCommit() {
var countryCount = root.organisationsByCountry.count();
var org = new Organisation();
org.country = "AT" + Math.random();
org.name = "Helma" + Math.random();
root.organisations.add(org);
res.commit(); // Commit Transaction
var country = root.organisationsByCountry.get(org.country);
assertEqual(countryCount + 1, root.organisationsByCountry.count());
assertNotNull(country);
assertEqual(country._prototype, "Country");
assertEqual(country._id, org.country);
org.remove();
res.commit(); // Commit Transaction
assertNull(root.organisationsByCountry.get(org.country));
assertEqual(countryCount, root.organisationsByCountry.count());
}
function testGroupByAddRemoveNoCommit() {
var countryCount = root.organisationsByCountry.count();
var org = new Organisation();
org.country = "AT" + Math.random();
org.name = "Helma" + Math.random();
root.organisations.add(org);
root.organisationsByCountry.add(org);
// FIXME HELMABUG: count does not get incremented immediately
assertEqual(countryCount + 1, root.organisationsByCountry.count());
var country = root.organisationsByCountry.get(org.country);
assertNotNull(country);
assertEqual(country._prototype, "Country");
assertEqual(country._id, org.country);
assertEqual(country.count(), 1);
assertEqual(country.get(0), org);
root.organisationsByCountry.removeChild(org);
org.remove();
// FIXME HELMABUG: country is still accessible at this point
// similar to http://helma.org/bugs/show_bug.cgi?id=551
assertNull(root.organisationsByCountry.get(org.country));
assertEqual(countryCount, root.organisationsByCountry.count());
}
function testGroupOrder() {
var org1 = new Organisation();
org1.country = "AT";
org1.name = "Helma" + Math.random();
root.organisations.add(org1);
var org2 = new Organisation();
org2.country = "CH01"; // pre-populated items have countries CH0000..C1234
org2.name = "Helma" + Math.random();
root.organisations.add(org2);
var org3 = new Organisation();
org3.country = "DE";
org3.name = "Helma" + Math.random();
root.organisations.add(org3);
var org4 = new Organisation();
org4.country = org3.country;
org4.name = "Helma" + Math.random();
root.organisations.add(org4);
res.commit();
// make sure that countries and organisations are sorted in decreasing order (as specified in type.properties)
var countries = root.organisationsByCountry.list();
assertEqual(countries.length, size + 3);
for (var i = 0; i < countries.length; i++) {
if (i>0) {
assertTrue(root.organisationsByCountry.get(i-1).groupname >= root.organisationsByCountry.get(i).groupname);
}
for (var j = 0; j < root.organisationsByCountry.get(i); j++) {
if (j > 0) {
assertTrue(root.organisationsByCountry.get(i).get(j-1).groupname >= root.organisationsByCountry.get(i).get(j).groupname);
}
}
}
org1.remove();
org2.remove();
org3.remove();
org4.remove();
}
function testGroupTransient() {
var temp = new Root();
var countryCount = temp.organisationsByCountry.count();
var org = new Organisation();
org.country = "AT" + Math.random();
org.name = "Helma" + Math.random();
temp.organisationsByCountry.add(org);
var country = temp.organisationsByCountry.get(org.country);
assertEqual(countryCount + 1, temp.organisationsByCountry.count());
assertNotNull(country);
assertEqual(country._prototype, "Country");
assertEqual(country.groupname, org.country);
// These don't work as org uses the parent from type.properties
// which is root.organisations. Not sure if this is a bug or not.
// assertEqual(country, org._parent);
// org.remove();
country.removeChild(org);
assertNull(root.organisationsByCountry.get(org.country));
assertEqual(countryCount, temp.organisationsByCountry.count());
}
function cleanup() {
var orgs = root.organisations.list();
for each (var org in orgs) {
org.remove();
}
}

View file

@ -0,0 +1,56 @@
tests = [
"testSimpleParent",
"testFallbackParent",
"testMountpoints"
];
var org;
var person1;
var person2;
function setup() {
org = new Organisation();
org.name = "Helma";
root.organisations.add(org);
person1 = new Person();
person1.name = "Hannes";
person1.organisation = org;
root.persons.add(person1);
person2 = new Person();
person2.name = "Michi";
root.persons.add(person2);
}
function testSimpleParent() {
assertEqual(org.href(), root.organisations.href() + org.name + "/");
assertEqual(root.organisations, org._parent);
assertEqual(root, org._parent._parent);
}
function testFallbackParent() {
assertEqual(person1.href(), person1.organisation.persons.href() + person1.name + "/");
assertEqual(person1.organisation.persons, person1._parent);
assertEqual(person2.href(), root.persons.href() + person2._id + "/");
assertEqual(root.persons, person2._parent);
}
function testMountpoints() {
assertEqual(root.someMountpoint._prototype, "SomeMountpoint");
assertEqual(root.someMountpoint._parent, root);
assertEqual(root.someMountpoint.href(), root.href() + "someMountpoint/");
assertEqual(org.someMountpoint._prototype, "SomeMountpoint");
assertEqual(org.someMountpoint._parent, org);
// FIXME: Helma-Bug ? mountpoints are converted to lower case ?
assertEqual(org.someMountpoint.href(), org.href() + "someMountpoint/");
}
function cleanup() {
org.remove();
person1.remove();
person2.remove();
}

View file

@ -0,0 +1,40 @@
tests = [
"testForward",
"testBackward",
];
function setup() {
var org = new Organisation();
var person = new Person();
org.name = "Acme Hovercraft";
person.name = "Murray Feather";
person.organisation = org;
org.person = person;
person.persist();
res.commit();
}
function testForward() {
app.clearCache();
person = root.persons.get(0);
org = root.organisations.get(0);
assertEqual(person.organisation, org);
assertEqual(person.organisation.name, org.name);
assertEqual("Acme Hovercraft", org.name);
}
function testBackward() {
app.clearCache();
var person = root.persons.get(0);
var org = root.organisations.get(0);
assertEqual(org.person, person);
assertEqual(org.person.name, person.name);
assertEqual("Murray Feather", person.name);
}
function cleanup() {
var person = root.persons.get(0);
var org = root.organisations.get(0);
org.remove();
person.remove();
}

319
src/dist/apps/test/tests/Skin.js vendored Normal file
View file

@ -0,0 +1,319 @@
var tests = [
"testCommentMacro",
"testDeepResolve",
"testDeepUnhandled",
"testDeep",
"testDeepFail",
"testDeepFailSilent",
"testJavaProp",
"testJavaMissing",
"testJavaMissingSilent",
"testJavaMissingVerbose",
"testUndefinedHandler",
"testJSProp",
"testJSMacro",
"testJSFunction",
"testJSMissing",
"testJSMissingSilent",
"testJSMissingVerbose",
"testDateFilter",
"testNestedRootMacro",
"testNestedParamMacro",
"testNestedResponseMacro",
"testNestedPrefixSuffix",
"testResponseProp",
"testResponseMacro",
"testResponseFunction",
"testResponseMissing",
"testResponseMissingSilent",
"testResponseMissingVerbose",
"testRootProp",
"testRootMacro",
"testRootMissing",
"testRootMissingSilent",
"testRootMissingVerbose",
"testSessionProp",
"testSessionMacro",
"testSessionFunction",
"testSessionMissing",
"testSessionMissingDefault",
"testSessionMissingSilent",
"testSessionMissingVerbose",
"testSessionDeepMissing",
"testSubskins"
];
var setup = function() {
res.handlers.color = new java.awt.Color["(int,int,int)"](0, 255, 0);
res.handlers.file = new java.io.File["(java.lang.String,java.lang.String)"](null, "file");
res.handlers.jsobject = {
banana: "yellow",
kiwi_macro: function() { return this.kiwiColor },
apple: function() {},
kiwiColor: "green"
};
res.data.date = new Date();
res.data.banana = "yellow";
res.data.kiwi_macro = function() { return "green" };
res.data.apple = function() {};
session.data.banana = "yellow";
session.data.kiwi_macro = function() { return "green" };
session.data.apple = function() {};
};
var testCommentMacro = function() {
var skin = createSkin("<% // this.foo bar=<% this.foobar %> FIXME %>ok");
var result = renderSkinAsString(skin);
assertEqual(result, "ok");
}
var testDeepResolve = function() {
res.handlers.deep = {
getMacroHandler: function(name) {
if (name != "foo") return null;
return {
bar_macro: function() {
return "ok";
}
}
}
}
var result = renderSkinAsString(createSkin("<% deep.foo.bar %>"));
assertEqual(result, "ok");
};
var testDeepUnhandled = function() {
res.handlers.deep = {
getMacroHandler: function(name) {
if (name != "foo") return null;
return {
onUnhandledMacro: function(name) {
if (name == "bar") return "ok";
}
}
}
}
var result = renderSkinAsString(createSkin("<% deep.foo.bar %>"));
assertEqual(result, "ok");
};
var testDeep = function() {
res.handlers.deep = {
foo: {
bar: "ok"
}
}
var result = renderSkinAsString(createSkin("<% deep.foo.bar %>"));
assertEqual(result, "ok");
};
var testDeepFail = function() {
var result = renderSkinAsString(createSkin("<% root.foo.bar %>"));
assertStringContains(result, "Unhandled");
var result = renderSkinAsString(createSkin("<% root.foo.bar failmode=silent %>"));
assertEqual(result, "");
};
var testDeepFailSilent = function() {
res.handlers.deep = {
foo: {}
};
var result = renderSkinAsString(createSkin("<% deep.foo.bar %>"));
assertEqual(result, "");
var result = renderSkinAsString(createSkin("<% deep.foo.bar failmode=verbose %>"));
assertStringContains(result, "Unhandled");
};
var testJavaProp = function() {
var result = renderSkinAsString(createSkin("<% color.green %>"));
assertEqual(result, "255");
result = renderSkinAsString(createSkin("<% color.red %>"));
assertEqual(result, "0");
};
var testJavaMissing = function() {
var result = renderSkinAsString(createSkin("<% colo.foo %>"));
assertStringContains(result, "Unhandled");
};
var testJavaMissingSilent = function() {
var result = renderSkinAsString(createSkin("<% color.foo failmode=silent default=ok %>"));
assertEqual(result, "ok");
};
var testJavaMissingVerbose = function() {
var result = renderSkinAsString(createSkin("<% color.foo failmode=verbose %>"));
assertStringContains(result, "Unhandled");
}
var testUndefinedHandler = function() {
var result = renderSkinAsString(createSkin("<% file.parentFile %>"));
assertEqual(result, "");
};
var testJSProp = function() {
var result = renderSkinAsString(createSkin("<% jsobject.banana %>"));
assertEqual(result, "yellow");
};
var testJSMacro = function() {
var result = renderSkinAsString(createSkin("<% jsobject.kiwi %>"));
assertEqual(result, "green");
};
var testJSFunction = function() {
var result = renderSkinAsString(createSkin("<% jsobject.apple failmode=silent %>"));
assertEqual(result, "");
};
var testJSMissing = function() {
var result = renderSkinAsString(createSkin("<% jsobject.papaya %>"));
assertEqual(result, "");
};
var testJSMissingSilent = function() {
var result = renderSkinAsString(createSkin("<% jsobject.papaya failmode=silent %>"));
assertEqual(result, "");
};
var testJSMissingVerbose = function() {
var result = renderSkinAsString(createSkin("<% jsobject.papaya failmode=verbose %>"));
assertStringContains(result, "Unhandled");
};
var testDateFilter = function() {
var result = renderSkinAsString(createSkin("<% root.date | isDate %>"));
assertEqual(result, "true");
};
var testNestedRootMacro = function() {
var skin = "<% echo <% root.date %> | isRootDate %>";
var result = renderSkinAsString(createSkin(skin));
assertEqual(result, "true");
}
var testNestedParamMacro = function() {
var skin = "<% echo <% param.date %> | isDate %>";
var result = renderSkinAsString(createSkin(skin), { date: new Date() });
assertEqual(result, "true");
}
var testNestedResponseMacro = function() {
var skin = "<% echo what=<% response.date %> | isResponseDate %>";
var result = renderSkinAsString(createSkin(skin));
assertEqual(result, "true");
};
var testNestedPrefixSuffix = function() {
var skin = "<% root.macro prefix=<% root.string %> suffix=<% root.macro %> %>";
var result = renderSkinAsString(createSkin(skin));
// root.macro changes suffix to "."
assertEqual(result, "rootroot.");
}
var testResponseProp = function() {
var result = renderSkinAsString(createSkin("<% response.banana %>"));
assertEqual(result, "yellow");
};
var testResponseMacro = function() {
var result = renderSkinAsString(createSkin("<% response.kiwi %>"));
assertEqual(result, "green");
};
var testResponseFunction = function() {
var result = renderSkinAsString(createSkin("<% response.apple failmode=silent %>"));
assertEqual(result, "");
};
var testResponseMissing = function() {
var result = renderSkinAsString(createSkin("<% response.papaya %>"));
assertEqual(result, "");
};
var testResponseMissingSilent = function() {
var result = renderSkinAsString(createSkin("<% response.papaya failmode=silent %>"));
assertEqual(result, "");
};
var testResponseMissingVerbose = function() {
var result = renderSkinAsString(createSkin("<% response.papaya failmode=verbose %>"));
assertStringContains(result, "Unhandled");
};
var testRootProp = function() {
var result = renderSkinAsString(createSkin("<% root.string %>"));
assertEqual(result, "root");
};
var testRootMacro = function() {
var result = renderSkinAsString(createSkin("<% root.macro %>"));
assertEqual(result, "root");
};
var testRootMissing = function() {
var result = renderSkinAsString(createSkin("<% root.undefinedmacro %>"));
assertStringContains(result, "Unhandled");
};
var testRootMissingSilent = function() {
var result = renderSkinAsString(createSkin("<% root.undefinedmacro failmode=silent %>"));
assertEqual(result, "");
};
var testRootMissingVerbose = function() {
var result = renderSkinAsString(createSkin("<% root.undefinedmacro failmode=verbose %>"));
assertStringContains(result, "Unhandled");
};
var testSessionProp = function() {
var result = renderSkinAsString(createSkin("<% session.banana %>"));
assertEqual(result, "yellow");
};
var testSessionMacro = function() {
var result = renderSkinAsString(createSkin("<% session.kiwi %>"));
assertEqual(result, "green");
};
var testSessionFunction = function() {
var result = renderSkinAsString(createSkin("<% session.apple failmode=silent %>"));
assertEqual(result, "");
};
var testSessionMissingDefault = function() {
var result = renderSkinAsString(createSkin("<% session.papaya default=nope %>"));
assertEqual(result, "nope");
};
var testSessionMissing = function() {
var result = renderSkinAsString(createSkin("<% session.papaya %>"));
assertEqual(result, "");
};
var testSessionMissingSilent = function() {
var result = renderSkinAsString(createSkin("<% session.papaya failmode=silent %>"));
assertEqual(result, "");
};
var testSessionMissingVerbose = function() {
var result = renderSkinAsString(createSkin("<% session.papaya failmode=verbose %>"));
assertStringContains(result, "Unhandled");
};
var testSessionDeepMissing = function() {
var result = renderSkinAsString(createSkin("<% session.user.name %>"));
assertStringContains(result, "Unhandled");
// assertEqual(result, "");
};
var testSubskins = function() {
var result = renderSkinAsString("subskins");
assertEqual(result, "mainskin");
result = renderSkinAsString("subskins#subskin1");
assertEqual(result, "subskin1");
result = renderSkinAsString("subskins#subskin2");
assertEqual(result, "subskin2");
};

68
src/dist/apps/test/tests/helma.Http.js vendored Normal file
View file

@ -0,0 +1,68 @@
var tests = [
"testSimple",
"testError",
"testNotFound",
"testRedirect",
"testRedirectNoFollow",
"testMaxResponseSize",
"testLongResponse"
];
app.addRepository("modules/helma/Http.js");
var http = new helma.Http();
var testSimple = function() {
var result = http.getUrl(root.href("hello"));
assertEqual(result.content, "Hello");
assertEqual(result.code, 200);
};
var testError = function() {
var result = http.getUrl(root.href("throwerror"));
assertEqual(result.content, "Error");
assertEqual(result.code, 500);
};
var testNotFound = function() {
var result = http.getUrl(root.href("nonExistingAction"));
assertEqual(result.content, "Not found");
assertEqual(result.code, 404);
};
var testRedirect = function() {
var result = http.getUrl(root.href("redirect"));
assertEqual(result.content, "Hello");
assertEqual(result.code, 200);
};
var testRedirectNoFollow = function() {
http.setFollowRedirects(false);
var result = null;
try {
result = http.getUrl(root.href("redirect"));
} finally {
http.setFollowRedirects(true);
}
assertEqual(result.content, "");
// response codes 302 and 303 are both ok
assertTrue(result.code == 302 || result.code == 303);
};
var testMaxResponseSize = function() {
http.setMaxResponseSize(3);
var error = null;
try {
http.getUrl(root.href("hello"));
} catch (err) {
error = err;
} finally {
http.setMaxResponseSize(null);
}
assertNotNull(error);
};
var testLongResponse = function() {
var result = http.getUrl(root.href("long"));
assertEqual(result.content, makeLongString());
};

347
src/dist/apps/test/tests/helma.Search.js vendored Normal file
View file

@ -0,0 +1,347 @@
var tests = [
"testConstructor",
"testGetDirectory",
"testGetRAMDirectory",
"testCreateIndex",
"testGetReaderWriter",
"testIndexLock",
"testDocument",
"testAddDocuments",
"testSearch"
];
app.addRepository("modules/helma/Search.js");
var indexName = "testindex";
var basePath = java.lang.System.getProperty("java.io.tmpdir");
var index;
/**
* Test preliminaries
*/
var setup = function() {
// check if there is a (leftover) directory with the same name
// in the system's temporary directory - if so throw an exception and stop
var dir = new helma.File(basePath, indexName);
if (dir.exists()) {
throw "There is already a directory '" + dir.getAbsolutePath() +
"', please remove it before trying to run test again";
}
return;
};
/**
* Test the helma.Search constructor to make sure Lucene is loaded
*/
var testConstructor = function() {
// should not throw an exception
var s = new helma.Search();
return;
};
/**
* Test getDirectory method
*/
var testGetDirectory = function() {
var search = new helma.Search();
assertThrows(function() {
search.getDirectory();
});
var dirs = [
new helma.File(basePath, indexName),
new File(basePath, indexName),
new java.io.File(basePath, indexName),
basePath + "/" + indexName
];
var dir, fsDir, dirPath;
for (var i in dirs) {
dir = dirs[i];
if (dir.constructor != String) {
dirPath = dir.getAbsolutePath();
} else {
dirPath = dir;
}
fsDir = search.getDirectory(dir);
assertNotNull(fsDir);
assertEqual(fsDir.getFile().getAbsolutePath(), dirPath);
}
return;
};
/**
* Test getRAMDirectory method
*/
var testGetRAMDirectory = function() {
var search = new helma.Search();
assertThrows(function() {
search.getDirectory();
});
var dirs = [
new helma.File(basePath, indexName),
new File(basePath, indexName),
new java.io.File(basePath, indexName),
basePath + "/" + indexName
];
var dir, ramDir;
for (var i in dirs) {
dir = dirs[i];
ramDir = search.getRAMDirectory(dir);
assertNotNull(ramDir);
}
return;
};
/**
* Test index creation - this method creates a RAMDirectory based
* index for testing and stores it in the global variable "index"
*/
var testCreateIndex = function() {
var search = new helma.Search();
// test creating a file based index
var fsDir = search.getDirectory(new helma.File(basePath, indexName));
index = search.createIndex(fsDir);
assertNotNull(index);
// explicitly test index.create(true)
assertTrue(index.create(true));
// test creating a ram based index
var ramDir = search.getRAMDirectory();
index = search.createIndex(ramDir);
assertNotNull(index);
// explicitly test index.create(true)
assertTrue(index.create(true));
assertEqual(index.constructor, helma.Search.Index);
assertEqual(index.size(), 0);
return;
};
/**
* Test getting index reader, writer and modifier
*/
var testGetReaderWriter = function() {
// test getReader
var reader = index.getReader();
assertNotNull(reader);
reader.close();
// test getWriter
var writer = index.getWriter();
assertNotNull(writer);
writer.close();
return;
};
/**
* Test index locking
*/
var testIndexLock = function() {
// test if the index is correctly locked when opening a writer
var writer = index.getWriter();
assertTrue(index.isLocked());
// test if getWriter() throws an exception when trying to open a second writer
assertThrows(function() {
index.getWriter();
});
writer.close();
assertFalse(index.isLocked());
return;
};
/**
* Test document constructor and methods
*/
var testDocument = function() {
var doc = new helma.Search.Document();
var f;
// test type conversion
f = new helma.Search.Document.Field("id", 1);
assertEqual(f.value.constructor, String);
assertEqual(f.value, "1");
var now = new Date();
f = new helma.Search.Document.Field("createtime", now);
assertEqual(f.dateValue.constructor, Date);
assertEqual(f.dateValue.getTime(), now.getTime() - (now.getTime() % 60000));
// test adding field with default store and index options
doc.addField(new helma.Search.Document.Field("id", 1));
f = doc.getField("id");
assertNotNull(f);
assertTrue(f.isStored());
assertTrue(f.isIndexed());
assertTrue(f.isTokenized());
// test adding date field with changed field options
f = new helma.Search.Document.Field("createtime", new Date(), {
store: "no",
index: "tokenized"
});
doc.addField(f);
f = doc.getField("createtime");
assertNotNull(f);
assertFalse(f.isStored());
assertTrue(f.isIndexed());
assertTrue(f.isTokenized());
// test deprecated way of calling addField()
doc.addField("title", "Just a test", {
"store": false,
"index": true,
"tokenize": false
});
f = doc.getField("title");
assertNotNull(f);
assertFalse(f.isStored());
assertTrue(f.isIndexed());
assertFalse(f.isTokenized());
// test getFields()
var fields = doc.getFields();
assertEqual(fields.length, 3);
assertEqual(fields[0].name, "id");
assertEqual(fields[1].name, "createtime");
assertEqual(fields[2].name, "title");
return;
};
/**
* Test adding documents
*/
var testAddDocuments = function() {
// test addDocument()
var doc = new helma.Search.Document();
doc.addField(new helma.Search.Document.Field("id", 1));
index.addDocument(doc);
assertEqual(index.size(), 1);
// test removeDocument()
index.removeDocument("id", 1);
assertEqual(index.size(), 0);
// test addDocuments() and removeDocuments() with an array
doc = new helma.Search.Document();
doc.addField(new helma.Search.Document.Field("id", 2));
index.addDocuments([doc]);
assertEqual(index.size(), 1);
index.removeDocuments("id", [2]);
assertEqual(index.size(), 0);
// test addDocuments() and removeDocuments() with a Hashtable as argument
var ht = new java.util.Hashtable();
ht.put("doc", doc);
index.addDocuments(ht);
ht = new java.util.Hashtable();
ht.put("id", 1);
ht.put("id", 2);
index.removeDocuments("id", ht);
assertEqual(index.size(), 0);
// test addDocuments() and removeDocuments() with a Vector as argument
var v = new java.util.Vector();
v.add(doc);
index.addDocuments(v);
v = new java.util.Vector();
v.add(1);
v.add(2);
index.removeDocuments("id", v);
assertEqual(index.size(), 0);
// test updateDocument
index.addDocument(doc);
doc = new helma.Search.Document();
doc.addField("id", 2);
index.updateDocument(doc, "id");
assertEqual(index.size(), 1);
// test count()
doc = new helma.Search.Document();
doc.addField("id", 3);
index.addDocument(doc);
assertEqual(index.count("id", 3), 1);
return;
};
/**
* Test searching the index
*/
var testSearch = function() {
// clear the index
index.create();
assertEqual(index.size(), 0);
// populate the index with test content
var names = [
"foo",
"bar",
"baz"
];
var now = new Date();
var doc;
names.forEach(function(name, idx) {
doc = new helma.Search.Document();
doc.addField("id", idx + 1);
doc.addField("parent", idx % 2);
doc.addField("name", name);
doc.addField("timestamp", new Date(now.getTime() - (idx * 1e6)));
index.addDocument(doc);
});
assertEqual(index.size(), 3);
var searcher = index.getSearcher();
assertNotNull(searcher);
assertNull(searcher.sortFields);
assertNotNull(searcher.getSearcher());
assertTrue(searcher.getSearcher() instanceof Packages.org.apache.lucene.search.IndexSearcher);
// test basic search
var q = new helma.Search.TermQuery("id", 1);
assertEqual(searcher.search(q), 1);
assertNotNull(searcher.hits);
assertEqual(searcher.hits.constructor, helma.Search.HitCollection);
assertEqual(searcher.hits.size(), 1);
var hit = searcher.hits.get(0);
assertNotNull(hit);
assertEqual(hit.constructor, helma.Search.Document);
assertEqual(hit.getField("name").constructor, helma.Search.Document.Field);
assertEqual(hit.getField("name").value, "foo");
// test date value conversion
assertEqual(hit.getField("timestamp").value.constructor, String);
assertEqual(hit.getField("timestamp").dateValue.constructor, Date);
// test query filter
var qf = new helma.Search.QueryFilter(new helma.Search.TermQuery("parent", 0));
q = new helma.Search.WildcardQuery("name", "ba*");
assertEqual(searcher.search(q, qf), 1);
assertEqual(searcher.hits.get(0).getField("name").value, names[2]);
// test sorting of hits
searcher.sortBy("id", true);
assertEqual(searcher.search(q), 2);
assertEqual(searcher.hits.get(0).getField("name").value, names[2]);
assertEqual(searcher.hits.get(1).getField("name").value, names[1]);
// test boolean query
q = new helma.Search.BooleanQuery();
q.addTerm("parent", "0");
assertEqual(q.toString(), "[(parent:0)]");
q = new helma.Search.BooleanQuery();
q.addTerm("parent", "0", "and");
assertEqual(q.toString(), "[+(parent:0)]");
q = new helma.Search.BooleanQuery();
q.addTerm("parent", "0", "not");
assertEqual(q.toString(), "[-(parent:0)]");
searcher.close();
return;
};
/**
* Cleanup
*/
var cleanup = function() {
// remove the directory containing the test index
var dir = new helma.File(basePath, indexName);
dir.removeDirectory();
return;
}

View file

@ -0,0 +1,11 @@
function onStart(name) {
if (!root.get('first')) {
root.name = 'root';
var firstNode = new HopObject();
firstNode.name = 'first';
root.add(firstNode)
var secondNode = new HopObject();
secondNode.name = 'second';
firstNode.add(secondNode)
}
}

View file

@ -0,0 +1,8 @@
function getChildElement(name) {
if (this.get(name))
return this.get(name);
var page = new Guide();
page.name = name;
page.parent = this;
return page;
}

View file

@ -0,0 +1,40 @@
<h1>actions</h1>
<p>Every request a Helma application receives is handled by an "action"
associated with the requested URL. For example, a request to
<a href="http://<% request.http_host %>/example">
http://<% request.http_host %>/example</a> will be handled by the
"example" action, defined at ./apps/welcome/code/Root/example.hac</p>
<pre>
res.write('Hello, this is the action defined \
at ./apps/welcome/code/Root/example.hac');
</pre>
<p>The file example.hac contains the Javascript code that Helma will
evaluate when handling that request. In this example, the code inside
the example.hac file automatically becomes a prototype method with an
"_action" suffix. By leveraging such conventions, Helma allows you to
structure your code in clean and uncluttered ways. Alternatively, you
can also define actions in generic Javascript files, an examples of
which can be found in ./apps/welcome/code/Root/example.js and tested via
the URL <a href="http://<% request.http_host %>/anotherexample">
http://<% request.http_host %>/anotherexample</a></p>
<pre>
function anotherexample_action() {
res.write('Hello again, this is the action \
defined in ./apps/welcome/Root/example.js');
}
</pre>
<p>Requests that do not specify a particular action are handled by the
"main" action. For example, a request to
<a href="http://<% request.http_host %>/">http://<% request.http_host %>/</a>
will be handled by the "main" action, defined at
./apps/welcome/code/Guide/main.hac</p>
<p>More information about the way Helma handles requests and maps them to
actions, and how Helma maps directories and filename extensions to
objects in the Javascript environment:
<br /><a href="http://dev.helma.org/docs/Request-Response-Cycle/">/docs/Request-Response-Cycle/</a></p>

View file

@ -0,0 +1,48 @@
<h1>applications</h1>
<p>Helma can serve multiple independent applications, each accessible
through a different mountpoint, using Javascript environments
running in their own global scope, and configurable to use separate
code repositories.</p>
<p>A Helma default installation, for example, is serving the applications
"manage" and "welcome" and makes them accessible through the
<a href="http://<% request.http_host %>/manage/">
http://<% request.http_host %>/manage/</a> and
<a href="http://<% request.http_host %>/">http://<% request.http_host %>/</a>
URLs respectively. The list of active applications is defined by the file
./apps.properties in Helma's home directory.</p>
<pre>
# Administrative application to manage all
# other apps on this server, accessible via its
# default mountpoint at http://host:port/manage
# and using its default repository at apps/manage
manage
# More complex example of an application with
# custom configuration:
welcome
welcome.mountpoint = /
welcome.repository.0 = apps/welcome/code/
welcome.repository.1 = modules/helmaTools.zip
welcome.static = apps/welcome/static
welcome.staticMountpoint = /static
welcome.staticHome = index.html,default.html
welcome.staticIndex = true
welcome.uploadLimit = 2048
</pre>
<p>Further application specific configurations can be defined in an app.properties
file inside an application's code repository. Examples of such a file you will
find in the "manage" app's default repository directory at
./apps/manage/app.properties and in the "welcome" application's repository at
./apps/welcome/code/app.properties.</p>
<p>More information about these files:
<br /><a href="http://dev.helma.org/docs/Properties+Files/apps.properties/">/docs/Properties+Files/apps.properties/</a>
<br /><a href="http://dev.helma.org/docs/Properties+Files/app.properties/">/docs/Properties+Files/app.properties/</a>
</p>

View file

@ -0,0 +1,56 @@
<h1>database mapping</h1>
<p>Helma allows you to map your HopObjects to relational database tables
instead of persisting them in the application's embedded XML database.</p>
<p>The list of available database connections is defined inside the file
./db.properties in Helma's home directory or for application specific
configurations in a db.properties file inside an application's code
repository.</p>
<pre>
myDataSource.url = jdbc:mysql://db.domain.com/space
myDataSource.driver = org.gjt.mm.mysql.Driver
myDataSource.user = username
myDataSource.password = xyz
</pre>
<p>In order to add the specified JDBC driver to the classpath, place it in
the ./lib/ext/ directory. Depending on the database system you are using,
you may want to <a href="http://developers.sun.com/product/jdbc/drivers">
download an appropriate JDBC driver</a>, for example a
<a href="http://www.mysql.com/downloads/api-jdbc-stable.html">driver for
MySQL</a>.</p>
<p>Using the <a href="sqlshell">SQLshell</a> from within your application,
you may at any time explore your database and issue SQL statements.
The SQLshell also allows you to map your database tables to properties
of your application's prototypes as desired. A simple configuration for
your object/relational mappings might look as follows:</p>
<pre>
_db = myDataSource
_table = PERSON
_id = ID
firstname = FIRSTNAME
lastname = LASTNAME
email = EMAIL
createtime = CREATETIME
modifytime = MODIFYTIME
</pre>
<p>These configurations would be placed in a type.properties file
inside the corresponding prototype directory, for example in
./apps/addressbook/Person/type.properties, when following the
"addressbook" tutorial.</p>
<p>To learn how Helma's relational database mapping is put to work and
how it relates and integrates with the other central aspects of the
framework, <a href="http://dev.helma.org/docs/Object-Relational+Mapping+Tutorial/">follow the
tutorial and build the full "addressbook" application</a>.</p>
<p>More information about the object/relational mapping of HopObject properties:
<br /><a href="http://dev.helma.org/docs/Properties+Files/db.properties/">/docs/Properties+Files/db.properties/</a>
<br /><a href="http://dev.helma.org/docs/Object-Relational+Mapping/">/docs/Object-Relational+Mapping/</a>
</p>

View file

@ -0,0 +1,37 @@
<h1>hopobjects</h1>
<p>HopObjects extend the standard Javascript object with Helma-specific
properties and functions. They are the central building blocks that allow
you to leverage the application framework Helma provides.</p>
<p>The main HopObject of every application is the "root" object. Every
HopObject can have a collection of attached additional HopObjects.
Each requested URL is resolved to a particular HopObject according
to these collections.</p>
<p>In the "welcome" application for example, a request to
<a href="http://<% request.http_host %>/first/second/">
http://<% request.http_host %>/first/second/</a> will be resolved by
checking the "root" object's collection for a HopObject named "first"
and the "first" object's collection for a HopObject named "second".</p>
<p>While this path resolution is by default performed based on the ID of
the attached HopObjects, collections can be custom configured to use
another property as access name. In this example, the HopObject prototype
is configured at ./apps/welcome/code/HopObject/type.properties to use the
"name" property for this purpose.</p>
<pre>
_children = collection(HopObject)
_children.accessname = name
name
</pre>
<p>When a new HopObject is added to such a collection, it is automatically
stored in Helma's embedded XML database. To see a detailed example of
how this works, go to <a href="http://<% request.http_host %>/first/">
http://<% request.http_host %>/first/</a> and add additional HopObjects.</p>
<p>Documentation of HopObject functions and built-in properties:
<br /><a href="http://helma.server-side-javascript.org/reference/HopObject.html">/reference/HopObject.html</a>
</p>

View file

@ -0,0 +1,33 @@
<h1>java packages</h1>
<p>Helma puts the whole wealth of Java libraries at your fingertips.
The "Packages" object in Helma's Javascript environment serves as
the doorway to leverage any Java packages in the CLASSPATH. You can
<a href="http://www.docjar.com/">add any Java packages</a> to the
CLASSPATH simply by putting the jar files in the ./lib/ext/ directory.</p>
<p>Any public methods that these Java classes define become callable from
your application's Javascript environment and you can create and work
with Java objects just like you do with Javascript objects. For example,
you could create a Java StringBuffer object and then append data to it
as follows:</p>
<pre>
var buffer = new Packages.java.lang.StringBuffer();
buffer.append('hello');
</pre>
<p>If your application makes extensive use of a Java class, it might be a
good idea to wrap that class in a Javascript prototype. That way, the
objects your applications works with become true Javascript objects, you
can control exactly which class methods are exposed to your application
and you can abstract the implementation, allowing you to change the Java
classes you use without requiring modifications to your application.</p>
<p>Various examples of such wrappers around Java classes can be found in the
helmaLib, which makes Mail, File, Ftp, Image, Search, SSH and Zip
functionality available in this way.</p>
<p>More information on how Helma makes Java scriptable:
<br /><a href="http://www.mozilla.org/rhino/ScriptingJava.html">/rhino/ScriptingJava</a>
</p>

View file

@ -0,0 +1,52 @@
<h1>macros</h1>
<p>Macros are methods of application logic that can be called through
custom macro tags contained in skins. Macros allow skins to pull
data from application logic, while other macro tags only push
pre-determined data to the skins.</p>
<p>You will find an example for such a skin in the "welcome" application
at ./apps/welcome/code/Root/example_using_macro.skin</p>
<pre>
&lt;p>This is an example of a skin calling a macro.&lt;/p>
&lt;p>You will find this skin at
./apps/welcome/code/Root/example_using_macro.skin&lt;/p>
&lt;p>This skin is rendered by the action defined at
./apps/welcome/code/Root/example_using_macro.hac&lt;/p>
&lt;p>The macro this skin calls is defined in
./apps/welcome/code/Root/example.js&lt;/p>
&lt;p>You can test it via the URL
&lt;a href="&lt;% this.pullLink part="url" %>">
&lt;% this.pullLink part="text" %>
&lt;/a>
&lt;/p>
</pre>
<p>In this example, the skin calls a "pullLink" macro twice, using a different
"part" parameter. Macro methods are defined using a corresponding function
name with a "_macro" suffix. The pullLink macro used in this example, you
will find defined in ./apps/welcome/code/Root/example.js</p>
<pre>
function pullLink_macro(params) {
switch (params.part) {
case 'text' :
return '/example_using_macro';
case 'url' :
return this.href('example_using_macro');;
}
}
</pre>
<p>You can test this macro and see the skin rendered via the URL
<a href="http://<% request.http_host %>/example_using_macro">
http://<% request.http_host %>/example_using_macro</a></p>
<p>Note that macros can again make use of skins, which may again contain
macro calls. This combination of skins and macros allows actions to
delegate the response generation through multiple tiers of "control"
and "presentation".</p>
<p>More information about macro tags and ways in which you can use custom defined macros:
<br /><a href="http://dev.helma.org/docs/Request-Response-Cycle/">/docs/Request-Response-Cycle/</a></p>

View file

@ -0,0 +1,41 @@
<h1>prototypes</h1>
<p>Helma's coding conventions revolve around the prototype based object
inheritance of Javascript. While Helma does not force you to leverage
these coding conventions, doing so will increase productivity and you
will achieve better maintainability due to a clean and well organized
code structure.</p>
<p>The HopObject prototype is the core prototype of every Helma application.
By default, other prototypes that you create will inherit from the
HopObject prototype. Every directory that you create inside your
application's code repository becomes automatically a prototype by that
name and will inherit the methods, actions, macros and skins that the
HopObject prototype provides.</p>
<p>In the "welcome" application's code repository at ./apps/welcome/code/
for example, you will find directories for the HopObject, Root and Guide
prototypes. Both the Root and Guide prototypes inherit automatically any
code from the HopObject prototype. Additionally, the Root prototype also
inherits from the Guide prototype, due to the "_extends" property that is
configured in ./apps/welcome/code/Root/type.properties</p>
<pre>
_extends = Guide
</pre>
<p>"Root" is the prototype of the application's root object. The root object
of the "welcome" application therefore uses the combined code from these
three prototypes, with code in "Root" overriding code from "Guide", which
in turn overrides code from "HopObject".</p>
<p>When Helma receives a request to <a href="http://<% request.http_host %>/">
http://<% request.http_host %>/</a> it will look for a "main" action to
handle the request. Since it will not find one in "Root", it will use the
one defined at ./apps/welcome/code/Guide/main.hac. Requests pointing to a
generic HopObject such as <a href="http://<% request.http_host %>/first/">
http://<% request.http_host %>/first/</a> on the other hand, will use the
main action defined at ./apps/welcome/code/HopObject/main.hac.</p>
<p>More information on how Helma puts prototypes to work:
<br /><a href="http://dev.helma.org/docs/Request-Response-Cycle/">/docs/Request-Response-Cycle/</a></p>

View file

@ -0,0 +1,14 @@
<div class="lead">
<p>Explore the introductions below and discover what you <br />
can do with Helma and Javascript on the server-side.</p>
</div>
<script> openbox('pageintro') </script>
<h3>introductions</h3>
<% response.listintro %>
<script> closebox() </script>
<script> openbox('content') </script>
<% response.content %>
<script> closebox() </script>

View file

@ -0,0 +1,44 @@
<h1>skins</h1>
<p>Helma allows you to cleanly separate presentation from application logic
through the use of skins. The skins are segments of HTML markup that can
contain macro tags, which are replaced with dynamic content when the
skin is rendered.</p>
<p>You will find an example for such a skin in the "welcome" application at
./apps/welcome/code/Root/example.skin</p>
<pre>
&lt;p>This is an example of a simple skin.&lt;/p>
&lt;p>You will find this skin at
./apps/welcome/code/Root/example.skin&lt;/p>
&lt;p>This skin is rendered by the action defined at
./apps/welcome/code/Root/example_using_skin.hac&lt;/p>
&lt;p>You can test it via the URL
&lt;a href="&lt;% response.pushLink %>">
&lt;% response.pushLinkText %>
&lt;/a>
&lt;/p>
</pre>
<p>The rendering of skins is controlled by an application's actions. In the
case of the "welcome" application, you will find an example of such an
action at ./apps/welcome/code/Root/example_using_skin.hac</p>
<pre>
res.data.pushLink = this.href('example_using_skin');
res.data.pushLinkText = '/example_using_skin';
this.renderSkin('example');
</pre>
<p>You can test this action and see the skin rendered via the URL
<a href="http://<% request.http_host %>/example_using_skin">
http://<% request.http_host %>/example_using_skin</a>
<p>Skins can contain various kinds of "macro tags" such as &lt;% response.pushLink %>
used in this example skin, where the value of a dynamic URL is determined by the
action and made available to the skin by setting the req.data.pushLink property.</p>
<p>More information about the way in which Helma defines and renders skins, and the
various kinds of available Macro Tags:
<br /><a href="http://dev.helma.org/docs/Request-Response-Cycle/">/docs/Request-Response-Cycle/</a></p>

View file

@ -0,0 +1,31 @@
<h1>static files</h1>
<p>The default mountpoint of a Helma application is always a code repository,
which means that requests will be handled by the application's Javascript
environment and will not reference specific server pages. Static files on
the other hand are served from separate "static" mountpoints.</p>
<p>In Helma's default installation, the "welcome" application is serving
static files from its "static" directory at ./apps/welcome/static/
and makes them accessible through URLs starting with
<a href="http://<% request.http_host %>/static/">
http://<% request.http_host %>/static/</a></p>
<p>For example, you should be able to access the file named "test.txt" inside
the ./apps/welcome/static/ directory via the URL
<a href="http://<% request.http_host %>/static/test.txt">
http://<% request.http_host %>/static/test.txt</a></p>
<p>Inside the ./apps.properties file, you will find the following settings,
which control the related behavior:</p>
<pre>
welcome.static = apps/welcome/static
welcome.staticMountpoint = /static
welcome.staticHome = index.html,default.html
welcome.staticIndex = true
</pre>
<p>More information about these and additional settings related to serving static files:
<br /><a href="http://dev.helma.org/docs/Properties+Files/apps.properties/">/docs/Properties+Files/apps.properties/</a>
</p>

View file

@ -0,0 +1,11 @@
<ul>
<li><a href="<% response.root %>intro/applications">applications</a></li>
<li><a href="<% response.root %>intro/staticfiles">static files</a></li>
<li><a href="<% response.root %>intro/actions">actions</a></li>
<li><a href="<% response.root %>intro/skins">skins</a></li>
<li><a href="<% response.root %>intro/macros">macros</a></li>
<li><a href="<% response.root %>intro/hopobjects">hopobjects</a></li>
<li><a href="<% response.root %>intro/prototypes">prototypes</a></li>
<li><a href="<% response.root %>intro/dbmapping">database mappings</a></li>
<li><a href="<% response.root %>intro/javapackages">java packages</a></li>
</ul>

View file

@ -0,0 +1,7 @@
<ul>
<li><a href="<% response.root %>tools/about_manage">manage</a></li>
<li><a href="<% response.root %>tools/about_shell">shell</a></li>
<li><a href="<% response.root %>tools/about_inspector">inspector</a></li>
<li><a href="<% response.root %>tools/about_sqlshell">sqlshell</a></li>
<li><a href="<% response.root %>tools/debugger">debugger</a></li>
</ul>

View file

@ -0,0 +1,14 @@
<ul>
<li><a href="http://dev.helma.org/">home</a></li>
<li><a href="http://dev.helma.org/mailing+lists/">mailing lists</a></li>
<li><a href="http://helma.server-side-javascript.org/hopbot/">irc channel</a></li>
<li><a href="http://dev.helma.org/docs/Documentation/">documentation</a></li>
<li><a href="http://helma.server-side-javascript.org/reference/">reference</a></li>
<li><a href="http://dev.helma.org/development/">project</a></li>
<li><a href="http://dev.helma.org/wiki/Helma+Roadmap/">roadmap</a></li>
<li><a href="http://dev.helma.org/bug+reporting/">bug reporting</a></li>
<li><a href="http://dev.helma.org/docs/Using+the+Source+Code+Repositories/">source</a></li>
<li><a href="http://dev.helma.org/wiki/">wiki</a></li>
<li><a href="http://dev.helma.org/wiki/Related+Projects/">related projects</a></li>
<li><a href="http://dev.helma.org/wiki/Sites+using+Helma/">sites using helma</a></li>
</ul>

View file

@ -0,0 +1,18 @@
// Prepare some response values used by the skins
res.data.href = this.href();
res.data.root = root.href();
// Render three nested skins
res.data.listtools = this.renderSkinAsString('list.tools');
res.data.listintro = this.renderSkinAsString('list.intro');
res.data.listwebsite = this.renderSkinAsString('list.website');
if (this.parent && this.parent.name) {
res.data.title = 'Welcome to Helma - '+ this.parent.name +' - '+ this.name;
res.data.content = this.renderSkinAsString( this.parent.name +'.'+ this.name );
res.data.body = this.renderSkinAsString( this.parent.name );
}
if (!res.data.body) {
res.data.title = 'Welcome to Helma - Overview';
res.data.body = this.renderSkinAsString('overview');
}
this.renderSkin('page');

View file

@ -0,0 +1,19 @@
<div class="lead">
<p>Welcome to Helma! Explore the tools, introductions and resources below and
discover what you can do with Helma and Javascript on the server-side.</p>
</div>
<script> openbox('tools') </script>
<h3>tools</h3>
<% response.listtools %>
<script> closebox() </script>
<script> openbox('intro') </script>
<h3>introductions</h3>
<% response.listintro %>
<script> closebox() </script>
<script> openbox('website') </script>
<h3>helma.org</h3>
<% response.listwebsite %>
<script> closebox() </script>

View file

@ -0,0 +1,21 @@
<h1>inspector</h1>
<p>The Inspector allows you to inspect and modify the properties of
HopObjects and to browse the HopObject tree. For example, you
can invoke the Inspector on the HopObject named "first" by
accessing the "inspector" action at
<a href="http://<% request.http_host %>/first/inspector">
http://<% request.http_host %>/first/inspector</a></p>
<img src="/static/guide/inspector.png" width="480" height="332" />
<p>Note that access to the Inspector is restricted for obvious security
reasons. If you have not yet done so, you will be directed on how
to configure administrative access when you attempt to use
this tool.</p>
<p>In order to be able to use the Inspector inside your own application,
you will need to add the helmaTools code repository to that
application. For example by adding modules/helmaTools.zip to the
<a href="/intro/applications">list of its repositories in the
./apps.properties file</a>.

View file

@ -0,0 +1,18 @@
<h1>manage</h1>
<p>The Manage application allows you to start and stop applications and
makes a variety of status information available. It also provides access
to the automatically generated API documentation of the application's
code repositories and libraries.</p>
<p>In Helma's default installation, the Manage application can be accessed
using the <a href="http://<% request.http_host %>/manage">
http://<% request.http_host %>/manage</a> mountpoint.</p>
<img src="/static/guide/manage.png" width="480" height="440" />
<p>Note that access to the Manage application is restricted for obvious
security reasons. You will first need to edit the ./server.properties
file and set adminAccess to your IP address. You then will be
directed on how to configure administrative access when you attempt to
use this tool.</p>

View file

@ -0,0 +1,31 @@
<h1>shell</h1>
<p>The Shell allows you to run commands and evaluate scripts within
your running application. This may be useful for administrative
and maintenance tasks for which you may not want to build a GUI
or pre-defined scripts. Certainly, the Shell can become very
useful during development and debugging.</p>
<p>By running commands you can inspect and manage data structures
beyond the capabilities of the Inspector. By running scripts you
can easily test and modify small portions of your application or
invoke actions, simulating specific circumstances and measuring
their performance.</p>
<p>For example, you can invoke the Shell on the HopObject
named "second" by accessing the "shell" action at
<a href="http://<% request.http_host %>/first/second/shell">
http://<% request.http_host %>/first/second/shell</a></p>
<img src="/static/guide/shell.png" width="480" height="475" />
<p>Note that access to the Shell is restricted for obvious security
reasons. If you have not yet done so, you will be directed on how
to configure administrative access when you attempt to use
this tool.</p>
<p>In order to be able to use the Shell inside your own application,
you will need to add the helmaTools code repository to that
application. For example by adding modules/helmaTools.zip to the
<a href="/intro/applications">list of its repositories in the
./apps.properties file</a>.

Some files were not shown because too many files have changed in this diff Show more