Merge remote-tracking branch 'helma/master'
Conflicts: .gitignore apps modules
This commit is contained in:
commit
ff7bba76cf
120 changed files with 14792 additions and 48 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -4,3 +4,6 @@ db/*
|
|||
lib/ext
|
||||
modules/
|
||||
server.properties
|
||||
classes/*
|
||||
launcher.jar
|
||||
lib/helma*.jar
|
||||
|
|
1
apps
1
apps
|
@ -1 +0,0 @@
|
|||
Subproject commit 05e6ad9f22321f173841e43ee35095aff0aa2309
|
67
apps/manage/Application/actions.js
Normal file
67
apps/manage/Application/actions.js
Normal 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());
|
||||
}
|
42
apps/manage/Application/functions.js
Normal file
42
apps/manage/Application/functions.js
Normal 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;
|
||||
}
|
11
apps/manage/Application/head.skin
Normal file
11
apps/manage/Application/head.skin
Normal file
|
@ -0,0 +1,11 @@
|
|||
<p><big>AppManager <% this.title %></big>
|
||||
<% this.description prefix="<br/>" %>
|
||||
<br/>
|
||||
->
|
||||
<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>
|
210
apps/manage/Application/macros.js
Normal file
210
apps/manage/Application/macros.js
Normal 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());
|
||||
}
|
||||
|
62
apps/manage/Application/main.skin
Normal file
62
apps/manage/Application/main.skin
Normal 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"> </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"> </td>
|
||||
<td class="list_property" align="left"><% this.users %> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="list_property" align="left">active evaluators</td>
|
||||
<td class="list_property" width="5"> </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"> </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"> </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"> </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"> </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"> </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"> </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"> </td><td class="list_property" valign="top">' itemsuffix='</td></tr>' %>
|
||||
</table>
|
||||
|
18
apps/manage/Application/navig_active.skin
Normal file
18
apps/manage/Application/navig_active.skin
Normal 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>
|
10
apps/manage/Application/navig_disabled.skin
Normal file
10
apps/manage/Application/navig_disabled.skin
Normal 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>
|
59
apps/manage/DocApplication/actions.js
Normal file
59
apps/manage/DocApplication/actions.js
Normal 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");
|
||||
}
|
31
apps/manage/DocApplication/frameset.skin
Normal file
31
apps/manage/DocApplication/frameset.skin
Normal 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>
|
||||
|
||||
|
24
apps/manage/DocApplication/functionindex.skin
Normal file
24
apps/manage/DocApplication/functionindex.skin
Normal 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>|
|
||||
|
97
apps/manage/DocApplication/functions.js
Normal file
97
apps/manage/DocApplication/functions.js
Normal 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;
|
||||
}
|
||||
|
||||
|
3
apps/manage/DocApplication/indexSeparator.skin
Normal file
3
apps/manage/DocApplication/indexSeparator.skin
Normal file
|
@ -0,0 +1,3 @@
|
|||
<tr><td class='headline'><a name="<% param.letter %>"><!-- --></a>
|
||||
<big><% param.letter %></big>
|
||||
</td></tr>
|
106
apps/manage/DocApplication/macros.js
Normal file
106
apps/manage/DocApplication/macros.js
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
10
apps/manage/DocApplication/prototypes.skin
Normal file
10
apps/manage/DocApplication/prototypes.skin
Normal 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 %>
|
||||
|
||||
|
||||
|
||||
|
||||
|
29
apps/manage/DocApplication/summary.skin
Normal file
29
apps/manage/DocApplication/summary.skin
Normal 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> |
|
||||
|
11
apps/manage/DocFunction/actions.js
Normal file
11
apps/manage/DocFunction/actions.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
function main_action() {
|
||||
if (checkAddress() == false)
|
||||
return;
|
||||
if (checkAuth() == false)
|
||||
return;
|
||||
res.data.body = this.renderSkinAsString("main");
|
||||
renderSkin("api");
|
||||
}
|
||||
|
||||
|
||||
|
7
apps/manage/DocFunction/asIndexItem.skin
Normal file
7
apps/manage/DocFunction/asIndexItem.skin
Normal file
|
@ -0,0 +1,7 @@
|
|||
<tr><td>
|
||||
<% this.link handler="false" %>
|
||||
- <% this.type %> in <% docprototype.name %>
|
||||
<br/>
|
||||
<% this.comment length="200" %>
|
||||
</td></tr>
|
||||
|
5
apps/manage/DocFunction/asLargeListItem.skin
Normal file
5
apps/manage/DocFunction/asLargeListItem.skin
Normal 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>
|
||||
|
8
apps/manage/DocFunction/asLargeListItemSkin.skin
Normal file
8
apps/manage/DocFunction/asLargeListItemSkin.skin
Normal 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>
|
||||
|
||||
|
||||
|
2
apps/manage/DocFunction/asListItem.skin
Normal file
2
apps/manage/DocFunction/asListItem.skin
Normal file
|
@ -0,0 +1,2 @@
|
|||
<% this.link %><br>
|
||||
|
1
apps/manage/DocFunction/asParentListItem.skin
Normal file
1
apps/manage/DocFunction/asParentListItem.skin
Normal file
|
@ -0,0 +1 @@
|
|||
<% this.link %>
|
10
apps/manage/DocFunction/functions.js
Normal file
10
apps/manage/DocFunction/functions.js
Normal 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;
|
||||
}
|
||||
|
||||
|
150
apps/manage/DocFunction/macros.js
Normal file
150
apps/manage/DocFunction/macros.js
Normal 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() + " (");
|
||||
var arr = this.listParameters();
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
res.write(arr[i]);
|
||||
if (i < arr.length - 1) {
|
||||
res.write(", ");
|
||||
}
|
||||
}
|
||||
res.write(")");
|
||||
} else if (this.getType() == this.MACRO) {
|
||||
res.write("<% ");
|
||||
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(" %>");
|
||||
} 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, >% %<-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("<%", "gim");
|
||||
sourcecode = sourcecode.replace(r, '<font color="#aa3300"><%');
|
||||
|
||||
r = new RegExp("%>", "gim");
|
||||
sourcecode = sourcecode.replace(r, '%></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("(".*?")", "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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
34
apps/manage/DocFunction/main.skin
Normal file
34
apps/manage/DocFunction/main.skin
Normal 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>
|
||||
|
||||
|
||||
|
18
apps/manage/DocPrototype/actions.js
Normal file
18
apps/manage/DocPrototype/actions.js
Normal 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");
|
||||
}
|
||||
|
1
apps/manage/DocPrototype/asInheritanceLink.skin
Normal file
1
apps/manage/DocPrototype/asInheritanceLink.skin
Normal file
|
@ -0,0 +1 @@
|
|||
extends Prototype <a href="<% this.href action="list" %>"><% this.name %></a>
|
16
apps/manage/DocPrototype/asParentList.skin
Normal file
16
apps/manage/DocPrototype/asParentList.skin
Normal 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>
|
||||
|
||||
|
||||
|
||||
|
||||
|
10
apps/manage/DocPrototype/asPrototypeList.skin
Normal file
10
apps/manage/DocPrototype/asPrototypeList.skin
Normal 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 />
|
4
apps/manage/DocPrototype/asSummary.skin
Normal file
4
apps/manage/DocPrototype/asSummary.skin
Normal file
|
@ -0,0 +1,4 @@
|
|||
<tr><td>
|
||||
<a href="<% this.href action="main" %>"><% this.name %></a><br/>
|
||||
<% this.comment length="200" %>
|
||||
</td></tr>
|
30
apps/manage/DocPrototype/functions.js
Normal file
30
apps/manage/DocPrototype/functions.js
Normal 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;
|
||||
}
|
10
apps/manage/DocPrototype/list.skin
Normal file
10
apps/manage/DocPrototype/list.skin
Normal 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>" %>
|
||||
|
165
apps/manage/DocPrototype/macros.js
Normal file
165
apps/manage/DocPrototype/macros.js
Normal 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;
|
||||
}
|
||||
}
|
81
apps/manage/DocPrototype/main.skin
Normal file
81
apps/manage/DocPrototype/main.skin
Normal 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'> </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'> </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'> </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'> </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'> </td></tr>"
|
||||
%>
|
||||
|
||||
<% this.parentPrototype skin="asParentList" %>
|
||||
</table>
|
||||
|
||||
<br/><br/>
|
||||
|
||||
<!-- % this.typeProperties % -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
9
apps/manage/DocPrototype/typeproperties.skin
Normal file
9
apps/manage/DocPrototype/typeproperties.skin
Normal 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>
|
||||
|
2
apps/manage/DocTag/author.skin
Normal file
2
apps/manage/DocTag/author.skin
Normal file
|
@ -0,0 +1,2 @@
|
|||
<li><b>Author</b><br/>
|
||||
<% this.text %>
|
2
apps/manage/DocTag/deprecated.skin
Normal file
2
apps/manage/DocTag/deprecated.skin
Normal file
|
@ -0,0 +1,2 @@
|
|||
<li><b>Deprecated</b><br/>
|
||||
<% this.text %>
|
1
apps/manage/DocTag/main.skin
Normal file
1
apps/manage/DocTag/main.skin
Normal file
|
@ -0,0 +1 @@
|
|||
<li><% this.text %>
|
3
apps/manage/DocTag/overrides.skin
Normal file
3
apps/manage/DocTag/overrides.skin
Normal file
|
@ -0,0 +1,3 @@
|
|||
<li><b>Overrides</b><br/>
|
||||
<% param.link %>
|
||||
|
2
apps/manage/DocTag/parameter.skin
Normal file
2
apps/manage/DocTag/parameter.skin
Normal file
|
@ -0,0 +1,2 @@
|
|||
<li><b>Parameter</b> <code><% this.name %></code>:<br/>
|
||||
<% this.text %>
|
2
apps/manage/DocTag/return.skin
Normal file
2
apps/manage/DocTag/return.skin
Normal file
|
@ -0,0 +1,2 @@
|
|||
<li><b>Returns</b><br>
|
||||
<% this.text %>
|
2
apps/manage/DocTag/see.skin
Normal file
2
apps/manage/DocTag/see.skin
Normal file
|
@ -0,0 +1,2 @@
|
|||
<li><b>See also</b><br>
|
||||
<% param.link %>
|
67
apps/manage/Global/api.skin
Normal file
67
apps/manage/Global/api.skin
Normal 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>
|
5
apps/manage/Global/basic.skin
Normal file
5
apps/manage/Global/basic.skin
Normal 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
apps/manage/Global/functions.js
Normal file
262
apps/manage/Global/functions.js
Normal 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
apps/manage/Global/global.skin
Normal file
14
apps/manage/Global/global.skin
Normal 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
apps/manage/Global/head.skin
Normal file
59
apps/manage/Global/head.skin
Normal 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
apps/manage/Global/macros.js
Normal file
18
apps/manage/Global/macros.js
Normal 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
apps/manage/Global/navig.skin
Normal file
30
apps/manage/Global/navig.skin
Normal 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>
|
20
apps/manage/Global/pwdfeedback.skin
Normal file
20
apps/manage/Global/pwdfeedback.skin
Normal 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>
|
28
apps/manage/Global/pwdform.skin
Normal file
28
apps/manage/Global/pwdform.skin
Normal 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>
|
153
apps/manage/Global/renderFunctions.js
Normal file
153
apps/manage/Global/renderFunctions.js
Normal 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 += ", ";
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
130
apps/manage/Root/actions.js
Normal file
130
apps/manage/Root/actions.js
Normal 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
apps/manage/Root/functions.js
Normal file
76
apps/manage/Root/functions.js
Normal 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
apps/manage/Root/macros.js
Normal file
284
apps/manage/Root/macros.js
Normal 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
apps/manage/Root/main.skin
Normal file
111
apps/manage/Root/main.skin
Normal 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"> </td>
|
||||
<td class="list_property" align="left"><% this.uptime %></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="list_property">version:</td>
|
||||
<td class="list_property" width="5"> </td>
|
||||
<td class="list_property" align="left"><% this.version %></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="list_property">homedir:</td>
|
||||
<td class="list_property" width="5"> </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"> </td>
|
||||
<td class="list_property" align="left"><% this.countSessions default=" " %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="list_property" nowrap valign="top">total requests / 5 min:</td>
|
||||
<td class="list_property" width="5"> </td>
|
||||
<td class="list_property" align="left"><% this.requestCount default=" " %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="list_property" norwrap valign="top">total errors / 5 min:</td>
|
||||
<td class="list_property" width="5"> </td>
|
||||
<td class="list_property" align="left"><% this.errorCount default=" " %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="list_property" valign="top">loaded extensions:</td>
|
||||
<td class="list_property" width="5"> </td>
|
||||
<td class="list_property" align="left"><% this.extensions default=" " %></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"> </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"> </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"> </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"> </td>
|
||||
<td class="list_property" align="left"><% this.jvm %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="list_property">javahome:</td>
|
||||
<td class="list_property" width="5"> </td>
|
||||
<td class="list_property" align="left"><% this.jvmHome %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="list_property">os:</td>
|
||||
<td class="list_property" width="5"> </td>
|
||||
<td class="list_property" align="left"><% this.os %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="list_property">localtime:</td>
|
||||
<td class="list_property" width="5"> </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"> </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"> </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"> </td><td class="list_property" align="left">' itemsuffix='</td></tr>' %>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
12
apps/manage/app.properties
Normal file
12
apps/manage/app.properties
Normal 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
apps/manage/class.properties
Normal file
27
apps/manage/class.properties
Normal 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
|
||||
|
17
apps/manage/readme.txt
Normal file
17
apps/manage/readme.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
To get the manage-application to work you must:
|
||||
|
||||
- add it to the apps.properties file with the following line:
|
||||
manage
|
||||
|
||||
- use helma distribution 1.5 or later.
|
||||
|
||||
- add the following properties to server.properties:
|
||||
|
||||
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
|
||||
|
|
@ -102,8 +102,8 @@
|
|||
<replace file="${build.work}/src/helma/main/Server.java"
|
||||
token="__builddate__" value="${TODAY}"/>
|
||||
<javac srcdir="${build.work}/src"
|
||||
source="1.4"
|
||||
target="1.4"
|
||||
source="1.5"
|
||||
target="1.5"
|
||||
destdir="${build.classes}"
|
||||
debug="${debug}"
|
||||
deprecation="${deprecation}"
|
||||
|
|
1
modules
1
modules
|
@ -1 +0,0 @@
|
|||
Subproject commit 29c112e07cb3f46882691e3184839cb7b2f4a67e
|
83
modules/core/Array.js
Normal file
83
modules/core/Array.js
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Array.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Adds useful methods to the JavaScript Array type.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/core/Array.js')
|
||||
*
|
||||
* @addon
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Check if this array contains a specific value.
|
||||
* @param {Object} val the value to check
|
||||
* @return {boolean} true if the value is contained
|
||||
*/
|
||||
Array.prototype.contains = function(val) {
|
||||
return this.indexOf(val) > -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the union set of a bunch of arrays
|
||||
* @param {Array} array1,... the arrays to unify
|
||||
* @return {Array} the union set
|
||||
*/
|
||||
Array.union = function() {
|
||||
var result = [];
|
||||
var map = {};
|
||||
for (var i=0; i<arguments.length; i+=1) {
|
||||
for (var n in arguments[i]) {
|
||||
var item = arguments[i][n];
|
||||
if (!map[item]) {
|
||||
result.push(item);
|
||||
map[item] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the intersection set of a bunch of arrays
|
||||
* @param {Array} array1,... the arrays to intersect
|
||||
* @return {Array} the intersection set
|
||||
*/
|
||||
Array.intersection = function() {
|
||||
var all = Array.union.apply(this, arguments);
|
||||
var result = [];
|
||||
for (var n in all) {
|
||||
var chksum = 0;
|
||||
var item = all[n];
|
||||
for (var i=0; i<arguments.length; i+=1) {
|
||||
if (arguments[i].contains(item))
|
||||
chksum += 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (chksum == arguments.length)
|
||||
result.push(item);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// prevent any newly added properties from being enumerated
|
||||
for (var i in Array)
|
||||
Array.dontEnum(i);
|
||||
for (var i in Array.prototype)
|
||||
Array.prototype.dontEnum(i);
|
196
modules/core/Date.js
Normal file
196
modules/core/Date.js
Normal file
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2005 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Date.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Adds useful methods to the JavaScript Date type.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/core/Date.js')
|
||||
*/
|
||||
|
||||
Date.ONESECOND = 1000;
|
||||
Date.ONEMINUTE = 60 * Date.ONESECOND;
|
||||
Date.ONEHOUR = 60 * Date.ONEMINUTE;
|
||||
Date.ONEDAY = 24 * Date.ONEHOUR;
|
||||
Date.ONEWEEK = 7 * Date.ONEDAY;
|
||||
Date.ONEMONTH = 30 * Date.ONEDAY;
|
||||
Date.ONEYEAR = 12 * Date.ONEMONTH;
|
||||
Date.ISOFORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
|
||||
|
||||
|
||||
/**
|
||||
* Format a Date to a string.
|
||||
* For details on the format pattern, see
|
||||
* http://java.sun.com/j2se/1.4.2/docs/api/java/text/SimpleDateFormat.html
|
||||
*
|
||||
* @param String Format pattern
|
||||
* @param Object Java Locale Object (optional)
|
||||
* @param Object Java TimeZone Object (optional)
|
||||
* @return String formatted Date
|
||||
* @see http://java.sun.com/j2se/1.4.2/docs/api/java/text/SimpleDateFormat.html
|
||||
*/
|
||||
Date.prototype.format = function (format, locale, timezone) {
|
||||
if (!format)
|
||||
return this.toString();
|
||||
var sdf = locale ? new java.text.SimpleDateFormat(format, locale)
|
||||
: new java.text.SimpleDateFormat(format);
|
||||
if (timezone && timezone != sdf.getTimeZone())
|
||||
sdf.setTimeZone(timezone);
|
||||
return sdf.format(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* set the date/time to UTC by subtracting
|
||||
* the timezone offset
|
||||
*/
|
||||
Date.prototype.toUtc = function() {
|
||||
this.setMinutes(this.getMinutes() + this.getTimezoneOffset());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* set the date/time to local time by adding
|
||||
* the timezone offset
|
||||
*/
|
||||
Date.prototype.toLocalTime = function() {
|
||||
this.setMinutes(this.getMinutes() - this.getTimezoneOffset());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* returns the difference between this and another
|
||||
* date object in milliseconds
|
||||
*/
|
||||
Date.prototype.diff = function(dateObj) {
|
||||
return this.getTime() - dateObj.getTime();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* return the timespan to current date/time or a different Date object
|
||||
* @param Object parameter object containing optional properties:
|
||||
* .now = String to use if difference is < 1 minute
|
||||
* .day|days = String to use for single|multiple day(s)
|
||||
* .hour|hours = String to use for single|multiple hour(s)
|
||||
* .minute|minutes = String to use for single|multiple minute(s)
|
||||
* .date = Date object to use for calculating the timespan
|
||||
* @return Object containing properties:
|
||||
* .isFuture = (Boolean)
|
||||
* .span = (String) timespan
|
||||
* @see Date.prototype.getAge
|
||||
* @see Date.prototype.getExpiry
|
||||
*/
|
||||
Date.prototype.getTimespan = function(param) {
|
||||
if (!param)
|
||||
param = {date: new Date()};
|
||||
else if (!param.date)
|
||||
param.date = new Date();
|
||||
|
||||
var result = {isFuture: this > param.date};
|
||||
var diff = Math.abs(param.date.diff(this));
|
||||
var age = {days: Math.floor(diff / Date.ONEDAY),
|
||||
hours: Math.floor((diff % Date.ONEDAY) / Date.ONEHOUR),
|
||||
minutes: Math.floor((diff % Date.ONEHOUR) / Date.ONEMINUTE)};
|
||||
|
||||
res.push();
|
||||
if (diff < Date.ONEMINUTE)
|
||||
res.write(param.now || "now");
|
||||
else {
|
||||
var arr = [{one: "day", many: "days"},
|
||||
{one: "hour", many: "hours"},
|
||||
{one: "minute", many: "minutes"}];
|
||||
for (var i in arr) {
|
||||
var value = age[arr[i].many];
|
||||
if (value != 0) {
|
||||
var prop = (value == 1 ? arr[i].one : arr[i].many);
|
||||
res.write(value);
|
||||
res.write(" ");
|
||||
res.write(param[prop] || prop);
|
||||
if (i < arr.length -1)
|
||||
res.write(param.delimiter || ", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
result.span = res.pop();
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* return the past timespan between this Date object and
|
||||
* the current Date or a different Date object
|
||||
* @see Date.prototype.getTimespan
|
||||
*/
|
||||
Date.prototype.getAge = function(param) {
|
||||
var age = this.getTimespan(param);
|
||||
if (!age.isFuture)
|
||||
return age.span;
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* return the future timespan between this Date object and
|
||||
* the current Date or a different Date object
|
||||
* @see Date.prototype.getTimespan
|
||||
*/
|
||||
Date.prototype.getExpiry = function(param) {
|
||||
var age = this.getTimespan(param);
|
||||
if (age.isFuture)
|
||||
return age.span;
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* checks if a date object equals another date object
|
||||
* @param Object Date object to compare
|
||||
* @param Int indicating how far the comparison should go
|
||||
* @return Boolean
|
||||
*/
|
||||
Date.prototype.equals = function(date, extend) {
|
||||
if (!extend)
|
||||
var extend = Date.ONEDAY;
|
||||
switch (extend) {
|
||||
case Date.ONESECOND:
|
||||
if (this.getSeconds() != date.getSeconds())
|
||||
return false;
|
||||
case Date.ONEMINUTE:
|
||||
if (this.getMinutes() != date.getMinutes())
|
||||
return false;
|
||||
case Date.ONEHOUR:
|
||||
if (this.getHours() != date.getHours())
|
||||
return false;
|
||||
case Date.ONEDAY:
|
||||
if (this.getDate() != date.getDate())
|
||||
return false;
|
||||
case Date.ONEMONTH:
|
||||
if (this.getMonth() != date.getMonth())
|
||||
return false;
|
||||
case Date.ONEYEAR:
|
||||
if (this.getFullYear() != date.getFullYear())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
// prevent any newly added properties from being enumerated
|
||||
for (var i in Date)
|
||||
Date.dontEnum(i);
|
||||
for (var i in Date.prototype)
|
||||
Date.prototype.dontEnum(i);
|
209
modules/core/Filters.js
Normal file
209
modules/core/Filters.js
Normal file
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2007 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile$
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Implements some useful macro filters.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/core/Filters.js')
|
||||
*/
|
||||
|
||||
app.addRepository('modules/core/String.js');
|
||||
|
||||
/**
|
||||
* Transforms a string to lowercase.
|
||||
*
|
||||
* @see String.prototype.toLowerCase
|
||||
*/
|
||||
function lowercase_filter(input) {
|
||||
return (input || "").toString().toLowerCase();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transforms a string to uppercase.
|
||||
*
|
||||
* @see String.prototype.toUpperCase
|
||||
*/
|
||||
function uppercase_filter(input) {
|
||||
return (input || "").toString().toUpperCase();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transforms the first Character of a string to uppercase.
|
||||
*
|
||||
* @see String.prototype.capitalize
|
||||
*/
|
||||
function capitalize_filter(input) {
|
||||
return (input || "").toString().capitalize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transforms the first Character of each word in a string
|
||||
* to uppercase.
|
||||
*
|
||||
* @see String.prototype.titleize
|
||||
*/
|
||||
function titleize_filter(input) {
|
||||
return (input || "").toString().titleize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cuts a String at a certain position, and
|
||||
* optionally appends a suffix, if truncation
|
||||
* has occurred.
|
||||
*
|
||||
* @see String.prototype.head
|
||||
* @param limit Maximum length
|
||||
* @param clipping Appended String, default is the empty String
|
||||
*/
|
||||
function truncate_filter(input, param, limit, clipping) {
|
||||
var limit = param.limit != null ? param.limit : limit;
|
||||
var clipping = param.clipping || clipping || "";
|
||||
return (input || "").toString().head(limit, clipping);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes leading and trailing whitespaces.
|
||||
*
|
||||
* @see String.prototype.trim
|
||||
*/
|
||||
function trim_filter(input) {
|
||||
return (input || "").toString().trim();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes all tags from a String.
|
||||
* Currently simply wraps Helma's stripTags-method.
|
||||
*
|
||||
* @see global.stripTags
|
||||
*/
|
||||
function stripTags_filter(input) {
|
||||
return stripTags((input || "").toString());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Escapes the characters in a String using XML entities.
|
||||
* Currently simply wraps Helma's encodeXml-method.
|
||||
*
|
||||
* @see global.encodeXml
|
||||
*/
|
||||
function escapeXml_filter(input) {
|
||||
return encodeXml((input || "").toString());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Escapes the characters in a String using HTML entities.
|
||||
*
|
||||
* @see http://www.google.com/codesearch?q=escapeHtml
|
||||
*/
|
||||
function escapeHtml_filter(input) {
|
||||
var replace = Packages.org.mortbay.util.StringUtil.replace;
|
||||
var str = (input || "").toString();
|
||||
return replace(replace(replace(replace(str, '&', '&'), '"', '"'), '>', '>'), '<', '<');
|
||||
}
|
||||
|
||||
var h_filter = escapeHtml_filter;
|
||||
|
||||
|
||||
/**
|
||||
* Escapes the characters in a String to be suitable
|
||||
* to use as an HTTP parameter value.
|
||||
*
|
||||
* @see http://www.google.com/codesearch?q=escapeUrl
|
||||
* @param charset Optional String. The name of a supported
|
||||
* character encoding.
|
||||
*/
|
||||
function escapeUrl_filter(input, param, charset) {
|
||||
var charset = param.charset || charset || app.getCharset();
|
||||
return java.net.URLEncoder.encode(input || "", charset);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Escapes a string so it may be used in JavaScript String
|
||||
* definitions.
|
||||
*/
|
||||
function escapeJavaScript_filter(input) {
|
||||
var replace = Packages.org.mortbay.util.StringUtil.replace;
|
||||
var str = (input || "").toString();
|
||||
return replace(replace(replace(replace(replace(str, '"', '\\"'), "'", "\\'"), '\n', '\\n'), '\r', '\\r'), '\t', '\\t');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replaces linebreaks with HTML linebreaks.
|
||||
*/
|
||||
function linebreakToHtml_filter(input) {
|
||||
var replace = Packages.org.mortbay.util.StringUtil.replace;
|
||||
var str = (input || "").toString();
|
||||
return replace(str, '\n', '<br />');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs a string replacement.
|
||||
*
|
||||
* @param old
|
||||
* @param new
|
||||
*/
|
||||
function replace_filter(input, param, oldString, newString) {
|
||||
var str = (input || "").toString();
|
||||
var oldString = param["old"] != null ? param["old"] : oldString;
|
||||
var newString = param["new"] != null ? param["new"] : newString;
|
||||
var replace = Packages.org.mortbay.util.StringUtil.replace;
|
||||
return replace(str, oldString, newString);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a substring. Simply wraps the javascript
|
||||
* method 'substring'.
|
||||
*
|
||||
* @see String.prototype.substring
|
||||
* @param from
|
||||
* @param to
|
||||
*/
|
||||
function substring_filter(input, param, from, to) {
|
||||
var from = param.from != null ? param.from : from;
|
||||
var to = param.to != null ? param.to : to;
|
||||
var str = (input || "").toString();
|
||||
return str.substring(from, to);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a formatted string representation of a Date.
|
||||
* Simply wraps javascripts Date.format-method.
|
||||
*
|
||||
* @see Date.prototype.format
|
||||
* @param format
|
||||
*/
|
||||
function dateFormat_filter(input, param, format) {
|
||||
var format = param.format || format;
|
||||
if (!input) {
|
||||
return;
|
||||
} else {
|
||||
return input.format(format);
|
||||
}
|
||||
}
|
79
modules/core/Global.js
Normal file
79
modules/core/Global.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2005 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Global.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Adds useful global macros.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/core/Global.js')
|
||||
*/
|
||||
|
||||
app.addRepository("modules/core/String.js");
|
||||
|
||||
|
||||
/**
|
||||
* write out a property contained in app.properties
|
||||
* @param Object containing the name of the property
|
||||
*/
|
||||
function property_macro(param, name) {
|
||||
res.write(getProperty(name || param.name) || String.NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wrapper to output a string from within a skin
|
||||
* just to be able to use different encodings
|
||||
* @param Object containing the string as text property
|
||||
*/
|
||||
function write_macro(param, text) {
|
||||
res.write(param.text || text || String.NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* renders the current datetime
|
||||
* @param Object containing a formatting string as format property
|
||||
*/
|
||||
function now_macro(param) {
|
||||
var d = new Date();
|
||||
if (param.format) {
|
||||
try {
|
||||
res.write(d.format(param.format));
|
||||
} catch (e) {
|
||||
res.write('<span title="' + e + '">[Invalid date format]</span>');
|
||||
}
|
||||
} else if (param.as == "timestamp") {
|
||||
res.write(d.getTime());
|
||||
} else {
|
||||
res.write(d);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* renders a global skin
|
||||
*/
|
||||
var skin_macro = function(param, name) {
|
||||
var skinName = name || param.name;
|
||||
if (skinName) {
|
||||
renderSkin(skinName, param);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
196
modules/core/HopObject.js
Normal file
196
modules/core/HopObject.js
Normal file
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2005 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: HopObject.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Adds useful methods to Helma's built-in HopObject prototype.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/core/HopObject.js')
|
||||
*/
|
||||
|
||||
app.addRepository("modules/core/Number.js");
|
||||
app.addRepository("modules/core/String.js");
|
||||
|
||||
|
||||
/**
|
||||
* Iterates over each child node of the HopObject.
|
||||
* @param {Function} callback The callback function to be
|
||||
* called for each child node. On every call the first
|
||||
* argument of this function is set to the current value
|
||||
* of the counter variable <code>i</code>.
|
||||
*/
|
||||
HopObject.prototype.forEach = function(callback) {
|
||||
if (!callback || callback instanceof Function == false) {
|
||||
return;
|
||||
}
|
||||
for (var i=0; i<this.size(); i+=1) {
|
||||
callback.call(this.get(i), i);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* macro returns the id of a HopObject
|
||||
*/
|
||||
HopObject.prototype.id_macro = function() {
|
||||
res.write(this._id);
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* macro returns the url for any hopobject
|
||||
*/
|
||||
HopObject.prototype.href_macro = function(param, action) {
|
||||
res.write(this.href(action || param.action || String.NULLSTR));
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* macro rendering a skin or displaying
|
||||
* its source (param.as == "source")
|
||||
*/
|
||||
HopObject.prototype.skin_macro = function(param, name) {
|
||||
var skinName = name || param.name;
|
||||
if (skinName) {
|
||||
if (param.as == "source") {
|
||||
var str = app.skinfiles[this._prototype][skinName];
|
||||
if (str && param.unwrap == "true") {
|
||||
str = str.unwrap();
|
||||
}
|
||||
} else {
|
||||
var str = this.renderSkinAsString(skinName, param);
|
||||
}
|
||||
res.write(str);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* this macro renders a text depending on
|
||||
* the value of a given property
|
||||
*/
|
||||
HopObject.prototype.switch_macro = function(param) {
|
||||
if (param.name) {
|
||||
res.write(this[param.name] ? param.on : param.off);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* generic macro that loops over the childobjects
|
||||
* and renders a specified skin for each of them
|
||||
* @param Object providing the following properties:
|
||||
* skin: the skin to render for each item (required)
|
||||
* collection: the collection containing the items
|
||||
* limit: max. number of items per page
|
||||
* (req.data.page determines the page number)
|
||||
* sort: property name to use for sorting
|
||||
* order: sort order (either "asc" or "desc")
|
||||
* itemPrefix: text to prepend to each items skin render
|
||||
* itemSuffix: text to append to each items skin render
|
||||
*/
|
||||
HopObject.prototype.loop_macro = function(param, collection) {
|
||||
if (!param.skin) {
|
||||
return;
|
||||
}
|
||||
if (!collection) {
|
||||
collection = param.collection;
|
||||
}
|
||||
var items = collection ? this[collection] : this;
|
||||
if (!items || !items.size || items.size() < 1) {
|
||||
return;
|
||||
}
|
||||
// set default values
|
||||
var min = 0, max = items.size();
|
||||
var pagesize = max;
|
||||
if (param.limit) {
|
||||
var n = parseInt(param.limit, 10);
|
||||
if (!isNaN(n)) {
|
||||
pagesize = n;
|
||||
}
|
||||
var pagenr = parseInt(req.data.page, 10);
|
||||
if (isNaN(pagenr)) {
|
||||
pagenr = 0;
|
||||
}
|
||||
min = Math.min(max, pagenr * pagesize);
|
||||
max = Math.min(max, min + pagesize);
|
||||
}
|
||||
if (param.sort) {
|
||||
var allitems = items.list();
|
||||
var test = allitems[0][param.sort];
|
||||
if (test == null || isNaN(test)) {
|
||||
var Sorter = String.Sorter;
|
||||
} else {
|
||||
var Sorter = Number.Sorter;
|
||||
}
|
||||
allitems.sort(new Sorter(param.sort, Sorter[param.order.toUpperCase()]));
|
||||
var itemlist = allitems.slice(min, max);
|
||||
} else {
|
||||
var itemlist = items.list(min, max);
|
||||
}
|
||||
var skinParam = {};
|
||||
var itemPrefix = param.itemPrefix || "";
|
||||
var itemSuffix = param.itemSuffix || "";
|
||||
for (var i=0; i<itemlist.length; i+=1) {
|
||||
skinParam.index = pagenr * pagesize + i + 1;
|
||||
res.write(itemPrefix);
|
||||
itemlist[i].renderSkin(param.skin, skinParam);
|
||||
res.write(itemSuffix);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Render the number of child nodes of the HopObject.
|
||||
* Three cases are distinguished which can be customized
|
||||
* by setting param.verbose to "true" and defining the
|
||||
* corresponding field of the <code>param</code>
|
||||
* argument:
|
||||
* <ol>
|
||||
* <li>param.none - not a single child node</li>
|
||||
* <li>param.one - exactly one child node</li>
|
||||
* <li>param.many - more than one child node</li>
|
||||
* </ol>
|
||||
* @param {Object} param The default macro parameter
|
||||
* @param {String} name The default name for a child node
|
||||
*/
|
||||
HopObject.prototype.size_macro = function(param, name) {
|
||||
var EMPTYSTR = "";
|
||||
var n = this.size();
|
||||
if (name) {
|
||||
var text;
|
||||
var plural = name.endsWith("s") ? "es" : "s";
|
||||
if (n > 0) {
|
||||
if (n > 1) {
|
||||
text = n + " " + name + plural;
|
||||
} else {
|
||||
text = (param.one !== null) ? param.one : "one " + name;
|
||||
}
|
||||
} else {
|
||||
text = (param.none !== null) ? param.none : "no " + name + plural;
|
||||
}
|
||||
res.write(text);
|
||||
} else {
|
||||
res.write(n);
|
||||
}
|
||||
return;
|
||||
};
|
179
modules/core/JSON.js
Normal file
179
modules/core/JSON.js
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: JSON.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Adds JSON methods to the Object, Array and String prototypes.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/core/JSON.js')
|
||||
*/
|
||||
|
||||
/*
|
||||
json.js
|
||||
2006-04-28 [http://www.json.org/json.js]
|
||||
|
||||
This file adds these methods to JavaScript:
|
||||
|
||||
object.toJSON()
|
||||
|
||||
This method produces a JSON text from an object. The
|
||||
object must not contain any cyclical references.
|
||||
|
||||
array.toJSON()
|
||||
|
||||
This method produces a JSON text from an array. The
|
||||
array must not contain any cyclical references.
|
||||
|
||||
string.parseJSON()
|
||||
|
||||
This method parses a JSON text to produce an object or
|
||||
array. It will return false if there is an error.
|
||||
*/
|
||||
|
||||
(function () {
|
||||
var m = {
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
},
|
||||
|
||||
s = {
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
array: function (x) {
|
||||
var a = ['['], b, f, i, l = x.length, v;
|
||||
for (i = 0; i < l; i += 1) {
|
||||
v = x[i];
|
||||
f = s[typeof v];
|
||||
if (f) {
|
||||
v = f(v);
|
||||
if (typeof v == 'string') {
|
||||
if (b) {
|
||||
a[a.length] = ',';
|
||||
}
|
||||
a[a.length] = v;
|
||||
b = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
a[a.length] = ']';
|
||||
return a.join('');
|
||||
},
|
||||
|
||||
'boolean': function (x) {
|
||||
return String(x);
|
||||
},
|
||||
|
||||
'null': function (x) {
|
||||
return "null";
|
||||
},
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
number: function (x) {
|
||||
return isFinite(x) ? String(x) : 'null';
|
||||
},
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
object: function (x) {
|
||||
if (x) {
|
||||
if (x instanceof Array) {
|
||||
return s.array(x);
|
||||
}
|
||||
var a = ['{'], b, f, i, v;
|
||||
for (i in x) {
|
||||
v = x[i];
|
||||
f = s[typeof v];
|
||||
if (f) {
|
||||
v = f(v);
|
||||
if (typeof v == 'string') {
|
||||
if (b) {
|
||||
a[a.length] = ',';
|
||||
}
|
||||
a.push(s.string(i), ':', v);
|
||||
b = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
a[a.length] = '}';
|
||||
return a.join('');
|
||||
}
|
||||
return 'null';
|
||||
},
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
string: function (x) {
|
||||
if (/["\\\x00-\x1f]/.test(x)) {
|
||||
x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
|
||||
var c = m[b];
|
||||
if (c) {
|
||||
return c;
|
||||
}
|
||||
c = b.charCodeAt();
|
||||
return '\\u00' +
|
||||
Math.floor(c / 16).toString(16) +
|
||||
(c % 16).toString(16);
|
||||
});
|
||||
}
|
||||
return '"' + x + '"';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This method produces a JSON text from an object.
|
||||
* The object must not contain any cyclical references.
|
||||
*/
|
||||
Object.prototype.toJSON = function () {
|
||||
return s.object(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* This method produces a JSON text from an array.
|
||||
* The array must not contain any cyclical references.
|
||||
*/
|
||||
Array.prototype.toJSON = function () {
|
||||
return s.array(this);
|
||||
};
|
||||
|
||||
Object.prototype.dontEnum("toJSON");
|
||||
Array.prototype.dontEnum("toJSON");
|
||||
return;
|
||||
})();
|
||||
|
||||
|
||||
/**
|
||||
* This method parses a JSON text to produce an object or
|
||||
* array. It will return false if there is an error.
|
||||
*/
|
||||
String.prototype.parseJSON = function () {
|
||||
try {
|
||||
return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(this.replace(/"(\\.|[^"\\])*"/g, ''))) && eval('(' + this + ')');
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
String.prototype.dontEnum("parseJSON");
|
80
modules/core/Number.js
Normal file
80
modules/core/Number.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Number.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Adds useful methods to the JavaScript Number type.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/core/Number.js')
|
||||
*/
|
||||
|
||||
/**
|
||||
* format a Number to a String
|
||||
* @param String Format pattern
|
||||
* @param java.util.Locale An optional Locale instance
|
||||
* @return String Number formatted to a String
|
||||
*/
|
||||
Number.prototype.format = function(fmt, locale) {
|
||||
var symbols;
|
||||
if (locale != null) {
|
||||
symbols = new java.text.DecimalFormatSymbols(locale);
|
||||
} else {
|
||||
symbols = new java.text.DecimalFormatSymbols();
|
||||
}
|
||||
var df = new java.text.DecimalFormat(fmt || "###,##0.##", symbols);
|
||||
return df.format(0 + this); // addition with 0 prevents exception
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* return the percentage of a Number
|
||||
* according to a given total Number
|
||||
* @param Int Total
|
||||
* @param String Format Pattern
|
||||
* @param java.util.Locale An optional Locale instance
|
||||
* @return Int Percentage
|
||||
*/
|
||||
Number.prototype.toPercent = function(total, fmt, locale) {
|
||||
if (!total)
|
||||
return (0).format(fmt, locale);
|
||||
var p = this / (total / 100);
|
||||
return p.format(fmt, locale);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* factory to create functions for sorting objects in an array
|
||||
* @param String name of the field each object is compared with
|
||||
* @param Number order (ascending or descending)
|
||||
* @return Function ready for use in Array.prototype.sort
|
||||
*/
|
||||
Number.Sorter = function(field, order) {
|
||||
if (!order)
|
||||
order = 1;
|
||||
return function(a, b) {
|
||||
return (a[field] - b[field]) * order;
|
||||
};
|
||||
};
|
||||
|
||||
Number.Sorter.ASC = 1;
|
||||
Number.Sorter.DESC = -1;
|
||||
|
||||
|
||||
// prevent any newly added properties from being enumerated
|
||||
for (var i in Number)
|
||||
Number.dontEnum(i);
|
||||
for (var i in Number.prototype)
|
||||
Number.prototype.dontEnum(i);
|
137
modules/core/Object.js
Normal file
137
modules/core/Object.js
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Object.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Adds useful methods to the JavaScript Object type.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/core/Object.js')
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copies the properties of this object into a clone.
|
||||
* @param {Object} clone The optional target object
|
||||
* @param {Boolean} recursive If true child objects are cloned as well, otherwise
|
||||
* the clone contains references to the child objects
|
||||
* @returns The resulting object
|
||||
*/
|
||||
Object.prototype.clone = function(clone, recursive) {
|
||||
|
||||
var getValue = function(value, recursive) {
|
||||
if ((value == null || typeof(value) !== "object") || recursive !== true) {
|
||||
return value;
|
||||
}
|
||||
return value.clone(null, recursive);
|
||||
};
|
||||
|
||||
if (typeof(this) === "object") {
|
||||
switch (this.constructor) {
|
||||
case Array:
|
||||
return this.map(function(value) {
|
||||
return getValue(value, recursive);
|
||||
});
|
||||
|
||||
case null: // e.g. macro parameter objects
|
||||
if (clone == null) {
|
||||
clone = {};
|
||||
}
|
||||
// continue below
|
||||
case Object:
|
||||
case HopObject:
|
||||
if (clone == null) {
|
||||
clone = new this.constructor();
|
||||
}
|
||||
for (var propName in this) {
|
||||
clone[propName] = getValue(this[propName], recursive);
|
||||
}
|
||||
return clone;
|
||||
|
||||
default:
|
||||
return new this.constructor(this.valueOf());
|
||||
}
|
||||
} else if (typeof(this) === "function" && this.constructor === RegExp) {
|
||||
return new RegExp(this.valueOf());
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* reduce an extended object (ie. a HopObject)
|
||||
* to a generic javascript object
|
||||
* @param HopObject the HopObject to be reduced
|
||||
* @return Object the resulting generic object
|
||||
*/
|
||||
Object.prototype.reduce = function(recursive) {
|
||||
var result = {};
|
||||
for (var i in this) {
|
||||
if (this[i] instanceof HopObject == false) {
|
||||
result[i] = this[i];
|
||||
} else if (recursive) {
|
||||
result[i] = this.reduce(true);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* print the contents of an object for debugging
|
||||
* @param Object the object to dump
|
||||
* @param Boolean recursive flag (if true, dump child objects, too)
|
||||
*/
|
||||
Object.prototype.dump = function(recursive) {
|
||||
var beginList = "<ul>";
|
||||
var endList = "</ul>";
|
||||
var beginItem = "<li>";
|
||||
var endItem = "</li>";
|
||||
var beginKey = "<strong>";
|
||||
var endKey = ":</strong> ";
|
||||
res.write(beginList);
|
||||
for (var p in this) {
|
||||
res.write(beginItem);
|
||||
res.write(beginKey);
|
||||
res.write(p);
|
||||
res.write(endKey);
|
||||
if (recursive && typeof this[p] == "object") {
|
||||
var recurse = true;
|
||||
var types = [Function, Date, String, Number];
|
||||
for (var i in types) {
|
||||
if (this[p] instanceof types[i]) {
|
||||
recurse = false
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (recurse == true)
|
||||
this[p].dump(true);
|
||||
else {
|
||||
res.write(this[p].toSource());
|
||||
}
|
||||
} else if (this[p]) {
|
||||
res.write(encode(this[p].toSource()));
|
||||
}
|
||||
res.write(endItem);
|
||||
}
|
||||
res.write(endList);
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
// prevent any newly added properties from being enumerated
|
||||
for (var i in Object)
|
||||
Object.dontEnum(i);
|
||||
for (var i in Object.prototype)
|
||||
Object.prototype.dontEnum(i);
|
673
modules/core/String.js
Normal file
673
modules/core/String.js
Normal file
|
@ -0,0 +1,673 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: String.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
|
||||
String.ANUMPATTERN = /[^a-zA-Z0-9]/;
|
||||
String.APATTERN = /[^a-zA-Z]/;
|
||||
String.NUMPATTERN = /[^0-9]/;
|
||||
String.FILEPATTERN = /[^a-zA-Z0-9-_\. ]/;
|
||||
String.HEXPATTERN = /[^a-fA-F0-9]/;
|
||||
// Email and URL RegExps contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
|
||||
// licensed unter MIT license - http://www.opensource.org/licenses/mit-license.php
|
||||
String.EMAILPATTERN = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i;
|
||||
String.URLPATTERN = /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;
|
||||
String.LEFT = -1
|
||||
String.BALANCE = 0
|
||||
String.RIGHT = 1
|
||||
String.ISOFORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";
|
||||
String.SPACE = " ";
|
||||
String.EMPTY = "";
|
||||
String.NULL = String.EMPTY; // to be deprecated?
|
||||
|
||||
/**
|
||||
* @fileoverview Adds useful methods to the JavaScript String type.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/core/String.js')
|
||||
*/
|
||||
|
||||
/**
|
||||
* checks if a date format pattern is correct
|
||||
* @return Boolean true if the pattern is correct
|
||||
*/
|
||||
String.prototype.isDateFormat = function() {
|
||||
try {
|
||||
new java.text.SimpleDateFormat(this);
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* parse a timestamp into a date object. This is used when users
|
||||
* want to set createtime explicitly when creating/editing stories.
|
||||
* @param String date format to be applied
|
||||
* @param Object Java TimeZone Object (optional)
|
||||
* @return Object contains the resulting date
|
||||
*/
|
||||
String.prototype.toDate = function(format, timezone) {
|
||||
var sdf = res.data._dateformat;
|
||||
if (!sdf) {
|
||||
sdf = new java.text.SimpleDateFormat(format);
|
||||
res.data._dateformat = sdf;
|
||||
} else if (format != sdf.toPattern())
|
||||
sdf.applyPattern(format);
|
||||
if (timezone && timezone != sdf.getTimeZone())
|
||||
sdf.setTimeZone(timezone);
|
||||
try {
|
||||
return new Date(sdf.parse(this).getTime());
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* function checks if the string passed contains any characters that
|
||||
* are forbidden in URLs and tries to create a java.net.URL from it
|
||||
* FIXME: probably deprecated -> helma.Url
|
||||
* @return Boolean
|
||||
* @see helma.Url.PATTERN
|
||||
*/
|
||||
String.prototype.isUrl = function() {
|
||||
return String.URLPATTERN.test(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* function checks if the string passed contains any characters
|
||||
* that are forbidden in image- or filenames
|
||||
* @return Boolean
|
||||
*/
|
||||
String.prototype.isFileName = function() {
|
||||
return !String.FILEPATTERN.test(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* function cleans the string passed as argument from any characters
|
||||
* that are forbidden or shouldn't be used in filenames
|
||||
* @return Boolean
|
||||
*/
|
||||
String.prototype.toFileName = function() {
|
||||
return this.replace(new RegExp(String.FILEPATTERN.source, "g"), String.NULL);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* function checks a string for a valid color value in hexadecimal format.
|
||||
* it may also contain # as first character
|
||||
* @returns Boolean false, if string length (without #) > 6 or < 6 or
|
||||
* contains any character which is not a valid hex value
|
||||
*/
|
||||
String.prototype.isHexColor = function() {
|
||||
var str = this;
|
||||
if (this.indexOf("#") == 0)
|
||||
str = this.substring(1);
|
||||
if (str.length != 6)
|
||||
return false;
|
||||
return !String.HEXPATTERN.test(str);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* converts a string into a hexadecimal color
|
||||
* representation (e.g. "ffcc33"). also knows how to
|
||||
* convert a color string like "rgb (255, 204, 51)".
|
||||
* @return String the resulting hex color (w/o "#")
|
||||
*/
|
||||
String.prototype.toHexColor = function() {
|
||||
if (this.startsWith("rgb")) {
|
||||
res.push();
|
||||
var col = this.replace(/[^0-9,]/g, String.NULL);
|
||||
var parts = col.split(",");
|
||||
for (var i in parts) {
|
||||
var num = parseInt(parts[i], 10);
|
||||
var hex = num.toString(16);
|
||||
res.write(hex.pad("0", 2, String.LEFT));
|
||||
}
|
||||
return res.pop();
|
||||
}
|
||||
var col = this.replace(new RegExp(String.HEXPATTERN.source), String.NULL);
|
||||
return col.toLowerCase().pad("0", 6, String.LEFT);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* function returns true if the string contains
|
||||
* only a-z and 0-9 (case insensitive!)
|
||||
* @return Boolean true in case string is alpha, false otherwise
|
||||
*/
|
||||
String.prototype.isAlphanumeric = function() {
|
||||
if (!this.length)
|
||||
return false;
|
||||
return !String.ANUMPATTERN.test(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* function cleans a string by throwing away all
|
||||
* non-alphanumeric characters
|
||||
* @return cleaned string
|
||||
*/
|
||||
String.prototype.toAlphanumeric = function() {
|
||||
return this.replace(new RegExp(String.ANUMPATTERN.source, "g"), String.NULL);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* function returns true if the string contains
|
||||
* only characters a-z
|
||||
* @return Boolean true in case string is alpha, false otherwise
|
||||
*/
|
||||
String.prototype.isAlpha = function() {
|
||||
if (!this.length)
|
||||
return false;
|
||||
return !String.APATTERN.test(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* function returns true if the string contains
|
||||
* only 0-9
|
||||
* @return Boolean true in case string is numeric, false otherwise
|
||||
*/
|
||||
String.prototype.isNumeric = function() {
|
||||
if (!this.length)
|
||||
return false;
|
||||
return !String.NUMPATTERN.test(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* transforms the first n characters of a string to uppercase
|
||||
* @param Number amount of characters to transform
|
||||
* @return String the resulting string
|
||||
*/
|
||||
String.prototype.capitalize = function(limit) {
|
||||
if (limit == null)
|
||||
limit = 1;
|
||||
var head = this.substring(0, limit);
|
||||
var tail = this.substring(limit, this.length);
|
||||
return head.toUpperCase() + tail.toLowerCase();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* transforms the first n characters of each
|
||||
* word in a string to uppercase
|
||||
* @return String the resulting string
|
||||
*/
|
||||
String.prototype.titleize = function() {
|
||||
var parts = this.split(" ");
|
||||
res.push();
|
||||
for (var i in parts) {
|
||||
res.write(parts[i].capitalize());
|
||||
if (i < parts.length-1)
|
||||
res.write(" ");
|
||||
}
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* translates all characters of a string into HTML entities
|
||||
* @return String translated result
|
||||
*/
|
||||
String.prototype.entitize = function() {
|
||||
res.push();
|
||||
for (var i=0; i<this.length; i++) {
|
||||
res.write("&#");
|
||||
res.write(this.charCodeAt(i).toString());
|
||||
res.write(";");
|
||||
}
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* breaks up a string into two parts called
|
||||
* head and tail at the given position
|
||||
* don't apply this to HTML, i.e. use stripTags() in advance
|
||||
* @param Number number of charactrers or of segments separated by the delimiter
|
||||
* @param String pre-/suffix to be pre-/appended to shortened string
|
||||
* @param String delimiter
|
||||
* @return Object containing head and tail properties
|
||||
*/
|
||||
String.prototype.embody = function(limit, clipping, delimiter) {
|
||||
if (typeof limit == "string")
|
||||
limit = parseInt(limit, 10);
|
||||
var result = {head: this, tail: String.NULL};
|
||||
if (!limit || limit < 1)
|
||||
return result;
|
||||
if (!delimiter || delimiter == String.NULL)
|
||||
result.head= this.substring(0, limit);
|
||||
else {
|
||||
var re = new RegExp ("(" + delimiter + "+)");
|
||||
result.head = this.split(re, 2*limit - 1).join(String.NULL);
|
||||
}
|
||||
if (result.head != this) {
|
||||
result.tail = this.substring(result.head.length).trim();
|
||||
if (result.tail) {
|
||||
if (clipping == null)
|
||||
clipping = "...";
|
||||
result.head = result.head.trim() + clipping;
|
||||
result.tail = clipping + result.tail;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* get the head of a string
|
||||
* @see String.prototype.embody()
|
||||
*/
|
||||
String.prototype.head = function(limit, clipping, delimiter) {
|
||||
return this.embody(limit, clipping, delimiter).head;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* get the tail of a string
|
||||
* @see String.prototype.embody()
|
||||
*/
|
||||
String.prototype.tail = function(limit, clipping, delimiter) {
|
||||
return this.embody(limit, clipping, delimiter).tail;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* set clip method out of compatibility/convenience reason
|
||||
* FIXME: we eventually have to get rid of this one...
|
||||
* @see String.prototype.head()
|
||||
*/
|
||||
String.prototype.clip = String.prototype.head;
|
||||
|
||||
|
||||
/**
|
||||
* function inserts a string every number of characters
|
||||
* @param Int number of characters after which insertion should take place
|
||||
* @param String string to be inserted
|
||||
* @param Boolean definitely insert at each interval position
|
||||
* @return String resulting string
|
||||
*/
|
||||
String.prototype.group = function(interval, str, ignoreWhiteSpace) {
|
||||
if (!interval || interval < 1)
|
||||
interval = 20;
|
||||
if (!str || this.length < interval)
|
||||
return this;
|
||||
res.push();
|
||||
for (var i=0; i<this.length; i=i+interval) {
|
||||
var strPart = this.substring(i, i+interval);
|
||||
res.write(strPart);
|
||||
if (ignoreWhiteSpace == true ||
|
||||
(strPart.length == interval && !/\s/g.test(strPart))) {
|
||||
res.write(str);
|
||||
}
|
||||
}
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* replace all linebreaks and optionally all w/br tags
|
||||
* @param Boolean flag indicating if html tags should be replaced
|
||||
* @param String replacement for the linebreaks / html tags
|
||||
* @return String the unwrapped string
|
||||
*/
|
||||
String.prototype.unwrap = function(removeTags, replacement) {
|
||||
if (replacement == null)
|
||||
replacement = String.NULL;
|
||||
var str = this.replace(/[\n|\r]/g, replacement);
|
||||
if (removeTags)
|
||||
str = str.replace(/<[w]?br *\/?>/g, replacement);
|
||||
return str;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* function calculates the md5 hash of a string
|
||||
* @return String md5 hash of the string
|
||||
*/
|
||||
String.prototype.md5 = function() {
|
||||
return Packages.helma.util.MD5Encoder.encode(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* function repeats a string the specified amount of times
|
||||
* @param Int amount of repetitions
|
||||
* @return String resulting string
|
||||
*/
|
||||
String.prototype.repeat = function(multiplier) {
|
||||
res.push();
|
||||
for (var i=0; i<multiplier; i++)
|
||||
res.write(this);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* function returns true if the string starts with
|
||||
* the string passed as argument
|
||||
* @param String string pattern to search for
|
||||
* @return Boolean true in case it matches the beginning
|
||||
* of the string, false otherwise
|
||||
*/
|
||||
String.prototype.startsWith = function(str, offset) {
|
||||
var javaObj = new java.lang.String(this);
|
||||
if (offset != null)
|
||||
return javaObj.startsWith(str, offset);
|
||||
return javaObj.startsWith(str);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* function returns true if the string ends with
|
||||
* the string passed as argument
|
||||
* @param String string pattern to search for
|
||||
* @return Boolean true in case it matches the end of
|
||||
* the string, false otherwise
|
||||
*/
|
||||
String.prototype.endsWith = function(str) {
|
||||
var javaObj = new java.lang.String(this);
|
||||
return javaObj.endsWith(str);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* fills a string with another string up to a desired length
|
||||
* @param String the filling string
|
||||
* @param Number the desired length of the resulting string
|
||||
* @param Number the direction which the string will be padded in:
|
||||
* -1: left 0: both (balance) 1: right
|
||||
* (you can use the constants String.LEFT,
|
||||
* String.BALANCE and String.RIGHT here as well.)
|
||||
* @return String the resulting string
|
||||
*/
|
||||
String.prototype.pad = function(str, len, mode) {
|
||||
if (str == null || len == null)
|
||||
return this;
|
||||
var diff = len - this.length;
|
||||
if (diff == 0)
|
||||
return this;
|
||||
var left, right = 0;
|
||||
if (mode == null || mode == String.RIGHT)
|
||||
right = diff;
|
||||
else if (mode == String.LEFT)
|
||||
left = diff;
|
||||
else if (mode == String.BALANCE) {
|
||||
right = Math.round(diff / 2);
|
||||
left = diff - right;
|
||||
}
|
||||
res.push();
|
||||
for (var i=0; i<left; i++)
|
||||
res.write(str);
|
||||
res.write(this);
|
||||
for (var i=0; i<right; i++)
|
||||
res.write(str);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* function returns true if a string contains the string
|
||||
* passed as argument
|
||||
* @param String string to search for
|
||||
* @param Int Position to start search
|
||||
* @param Boolean
|
||||
*/
|
||||
String.prototype.contains = function(str, fromIndex) {
|
||||
if (this.indexOf(str, fromIndex ? fromIndex : 0) > -1)
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* function compares a string with the one passed as argument
|
||||
* using diff
|
||||
* @param String String to compare against String object value
|
||||
* @param String Optional regular expression string to use for
|
||||
* splitting. If not defined, newlines will be used.
|
||||
* @return Object Array containing one JS object for each line
|
||||
* with the following properties:
|
||||
* .num Line number
|
||||
* .value String line if unchanged
|
||||
* .deleted Obj Array containing deleted lines
|
||||
* .inserted Obj Array containing added lines
|
||||
*/
|
||||
String.prototype.diff = function(mod, separator) {
|
||||
// if no separator use line separator
|
||||
var regexp = (typeof(separator) == "undefined") ?
|
||||
new RegExp("\r\n|\r|\n") :
|
||||
new RegExp(separator);
|
||||
// split both strings into arrays
|
||||
var orig = this.split(regexp);
|
||||
var mod = mod.split(regexp);
|
||||
// create the Diff object
|
||||
var diff = new Packages.helma.util.Diff(orig, mod);
|
||||
// get the diff.
|
||||
var d = diff.diff();
|
||||
if (!d)
|
||||
return null;
|
||||
|
||||
var max = Math.max(orig.length, mod.length);
|
||||
var result = new Array();
|
||||
for (var i=0;i<max;i++) {
|
||||
var line = result[i];
|
||||
if (!line) {
|
||||
line = new Object();
|
||||
line.num = (i+1);
|
||||
result[i] = line;
|
||||
}
|
||||
if (d && i == d.line1) {
|
||||
if (d.deleted) {
|
||||
var del = new Array();
|
||||
for (var j=d.line0; j<d.line0+d.deleted; j++)
|
||||
del[del.length] = orig[j];
|
||||
line.deleted = del;
|
||||
}
|
||||
if (d.inserted) {
|
||||
var ins = new Array();
|
||||
for (var j=d.line1; j<d.line1+d.inserted; j++)
|
||||
ins[ins.length] = mod[j];
|
||||
line.inserted = ins;
|
||||
}
|
||||
i = d.line1 + d.inserted -1;
|
||||
d = d.link;
|
||||
} else {
|
||||
line.value = mod[i];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* remove leading and trailing whitespace
|
||||
*/
|
||||
String.prototype.trim = function () {
|
||||
var s = new java.lang.String(this);
|
||||
return String(s.trim());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* returns true if the string looks like an e-mail
|
||||
*/
|
||||
String.prototype.isEmail = function() {
|
||||
return String.EMAILPATTERN.test(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* returns the amount of occurences of one string in another
|
||||
*/
|
||||
String.prototype.count = function(str) {
|
||||
var count = 0;
|
||||
var offset = 0;
|
||||
while ((offset = this.indexOf(str, offset)) > -1) {
|
||||
count += 1;
|
||||
offset += 1;
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* returns the string encoded using the base64 algorithm
|
||||
*/
|
||||
String.prototype.enbase64 = function() {
|
||||
var bytes = new java.lang.String(this) . getBytes();
|
||||
return new Packages.sun.misc.BASE64Encoder().encode(bytes);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* returns the decoded string using the base64 algorithm
|
||||
*/
|
||||
String.prototype.debase64 = function() {
|
||||
var bytes = new Packages.sun.misc.BASE64Decoder().decodeBuffer(this);
|
||||
return String(new java.lang.String(bytes));
|
||||
};
|
||||
|
||||
|
||||
// wrapper methods for string-related
|
||||
// global helma functions
|
||||
|
||||
String.prototype.encode = function() {
|
||||
return encode(this);
|
||||
};
|
||||
|
||||
String.prototype.encodeXml = function() {
|
||||
return encodeXml(this);
|
||||
};
|
||||
|
||||
String.prototype.encodeForm = function() {
|
||||
return encodeForm(this);
|
||||
};
|
||||
|
||||
String.prototype.format = function() {
|
||||
return format(this);
|
||||
};
|
||||
|
||||
String.prototype.stripTags = function() {
|
||||
return stripTags(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* factory to create functions for sorting objects in an array
|
||||
* @param String name of the field each object is compared with
|
||||
* @param Number order (ascending or descending)
|
||||
* @return Function ready for use in Array.prototype.sort
|
||||
*/
|
||||
String.Sorter = function(field, order) {
|
||||
if (!order)
|
||||
order = 1;
|
||||
var key = field + ":" + order;
|
||||
if (!String.Sorter.cache[key]) {
|
||||
String.Sorter.cache[key] = function(a, b) {
|
||||
var str1 = String(a[field] || String.NULL).toLowerCase();
|
||||
var str2 = String(b[field] || String.NULL).toLowerCase();
|
||||
if (str1 > str2)
|
||||
return order * 1;
|
||||
if (str1 < str2)
|
||||
return order * -1;
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
return String.Sorter.cache[key];
|
||||
};
|
||||
|
||||
String.Sorter.ASC = 1;
|
||||
String.Sorter.DESC = -1;
|
||||
String.Sorter.cache = {};
|
||||
|
||||
|
||||
/**
|
||||
* create a string from a bunch of substrings
|
||||
* @param String one or more strings as arguments
|
||||
* @return String the resulting string
|
||||
*/
|
||||
String.compose = function() {
|
||||
res.push();
|
||||
for (var i=0; i<arguments.length; i++)
|
||||
res.write(arguments[i]);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* creates a random string (numbers and chars)
|
||||
* @param len length of key
|
||||
* @param mode determines which letters to use. null or 0 = all letters;
|
||||
* 1 = skip 0, 1, l and o which can easily be mixed with numbers;
|
||||
* 2 = use numbers only
|
||||
* @returns random string
|
||||
*/
|
||||
String.random = function(len, mode) {
|
||||
if (mode == 2) {
|
||||
var x = Math.random() * Math.pow(10,len);
|
||||
return Math.floor(x);
|
||||
}
|
||||
var keystr = String.NULL;
|
||||
for (var i=0; i<len; i++) {
|
||||
var x = Math.floor((Math.random() * 36));
|
||||
if (mode == 1) {
|
||||
// skip 0,1
|
||||
x = (x<2) ? x + 2 : x;
|
||||
// don't use the letters l (charCode 21+87) and o (24+87)
|
||||
x = (x==21) ? 22 : x;
|
||||
x = (x==24) ? 25 : x;
|
||||
}
|
||||
if (x<10) {
|
||||
keystr += String(x);
|
||||
} else {
|
||||
keystr += String.fromCharCode(x+87);
|
||||
}
|
||||
}
|
||||
return keystr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* append one string onto another and add some "glue"
|
||||
* if none of the strings is empty or null.
|
||||
* @param String the first string
|
||||
* @param String the string to be appended onto the first one
|
||||
* @param String the "glue" to be inserted between both strings
|
||||
* @return String the resulting string
|
||||
*/
|
||||
String.join = function(str1, str2, glue) {
|
||||
if (glue == null)
|
||||
glue = String.NULL;
|
||||
if (str1 && str2)
|
||||
return str1 + glue + str2;
|
||||
else if (str2)
|
||||
return str2;
|
||||
return str1;
|
||||
};
|
||||
|
||||
|
||||
// prevent any newly added properties from being enumerated
|
||||
for (var i in String)
|
||||
String.dontEnum(i);
|
||||
for (var i in String.prototype)
|
||||
String.prototype.dontEnum(i);
|
28
modules/core/all.js
Normal file
28
modules/core/all.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: all.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
// convenience SingleFileRepository to load all the
|
||||
// Javascript library files in ./modules/core
|
||||
|
||||
app.addRepository('modules/core/Array.js');
|
||||
app.addRepository('modules/core/Date.js');
|
||||
app.addRepository('modules/core/Number.js');
|
||||
app.addRepository('modules/core/Object.js');
|
||||
app.addRepository('modules/core/String.js');
|
||||
app.addRepository('modules/core/HopObject.js');
|
||||
app.addRepository('modules/core/Global.js');
|
||||
app.addRepository('modules/core/JSON.js');
|
||||
app.addRepository('modules/core/Filters.js');
|
145
modules/helma/Aspects.js
Normal file
145
modules/helma/Aspects.js
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2008 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Aspects.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Methods of the helma.Aspects module.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/helma/Aspects.js')
|
||||
*/
|
||||
|
||||
/**
|
||||
* Define the global namespace if not existing
|
||||
*/
|
||||
if (!global.helma) {
|
||||
global.helma = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Library for adding Aspects
|
||||
* <br /><br />
|
||||
* Provides static methods to wrap existing functions
|
||||
* inside a javascript closure in order to add additional
|
||||
* behavior without overriding the existing one.
|
||||
* <br /><br />
|
||||
* Based on code by roman porotnikov,
|
||||
* http://www.jroller.com/page/deep/20030701
|
||||
* <br /><br />
|
||||
* Note: Each prototype that uses aspects must implement a method
|
||||
* onCodeUpdate() to prevent aspects being lost when the prototype
|
||||
* is re-compiled
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
helma.Aspects = function() {
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/** @ignore */
|
||||
helma.Aspects.toString = function() {
|
||||
return "[helma.Aspects]";
|
||||
};
|
||||
|
||||
|
||||
/** @ignore */
|
||||
helma.Aspects.prototype.toString = function() {
|
||||
return "[helma.Aspects Object]";
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds a function to be called before the orginal function.
|
||||
* <br /><br />
|
||||
* The return value of the added function needs to provide the
|
||||
* array of arguments that is passed to the original function.
|
||||
* The added function receives an array of the original arguments,
|
||||
* the original function and the scope object of the original
|
||||
* function as its parameters.
|
||||
*
|
||||
* @param {Object} obj The object of which the original function is a property
|
||||
* @param {String} fname The property name of the original function
|
||||
* @param {Function} before The function to be called before the original function
|
||||
* @returns Function A new function, wrapping the original function
|
||||
* @type Function
|
||||
*/
|
||||
helma.Aspects.prototype.addBefore = function(obj, fname, before) {
|
||||
var oldFunc = obj[fname];
|
||||
obj[fname] = function() {
|
||||
return oldFunc.apply(this, before(arguments, oldFunc, this));
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds a function to be called after an existing function.
|
||||
* <br /><br />
|
||||
* The return value of the original function is passed to the
|
||||
* added function as its first argument. In addition, the added
|
||||
* function also receives an array of the original arguments,
|
||||
* the original function and the scope object of the original
|
||||
* function as additional parameters.
|
||||
*
|
||||
* @param {Object} obj as Object, the object of which the original function is a property
|
||||
* @param {String} fname as String, the property name of the original function
|
||||
* @param {Function} after as Function, the function to be called after the original function
|
||||
* @returns Function A new function, wrapping the original function
|
||||
* @type Function
|
||||
*/
|
||||
helma.Aspects.prototype.addAfter = function(obj, fname, after) {
|
||||
var oldFunc = obj[fname];
|
||||
obj[fname] = function() {
|
||||
return after(oldFunc.apply(this, arguments), arguments, oldFunc, this);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Wraps an additional function around the original function.
|
||||
* <br /><br />
|
||||
* The added function receives as its arguments an array of the original
|
||||
* arguments, the original function and the scope object of the original
|
||||
* function. The original function is not called directly and needs
|
||||
* to be invoked by the added function.
|
||||
*
|
||||
* @param {Object} obj as Object, the object of which the original function is a property
|
||||
* @param {String} fname as String, the property name of the original function
|
||||
* @param {Function} around as Function, the function to be called inside the original function
|
||||
* @returns Function A new function, wrapping the original function
|
||||
* @type Function
|
||||
*/
|
||||
helma.Aspects.prototype.addAround = function(obj, fname, around) {
|
||||
var oldFunc = obj[fname];
|
||||
obj[fname] = function() {
|
||||
return around(arguments, oldFunc, this);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
helma.lib = "Aspects";
|
||||
helma.dontEnum(helma.lib);
|
||||
for (var i in helma[helma.lib])
|
||||
helma[helma.lib].dontEnum(i);
|
||||
for (var i in helma[helma.lib].prototype)
|
||||
helma[helma.lib].prototype.dontEnum(i);
|
||||
delete helma.lib;
|
||||
|
||||
|
||||
helma.aspects = new helma.Aspects();
|
||||
helma.dontEnum("aspects");
|
201
modules/helma/Chart.js
vendored
Normal file
201
modules/helma/Chart.js
vendored
Normal file
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Chart.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the helma.Chart prototype
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/helma/Chart.js')
|
||||
*/
|
||||
|
||||
// take care of any dependencies
|
||||
app.addRepository('modules/helma/jxl.jar');
|
||||
|
||||
/**
|
||||
* Define the global namespace if not existing
|
||||
*/
|
||||
if (!global.helma) {
|
||||
global.helma = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of helma.Chart
|
||||
* @class Instances of this class are capable of reading
|
||||
* Excel spreadsheets and rendering them as XHTML table. Internally
|
||||
* helma.Chart uses the <a href="http://www.jexcelapi.org/ ">Java Excel API</a>
|
||||
* by <a href="http://www.andykhan.com/">Andy Khan</a>.
|
||||
* @param {String} fpath The path to the spreadsheet file
|
||||
* @param {String} prefix An optional prefix to use for all
|
||||
* stylesheet classes within the rendered table
|
||||
* @param {String} sheetName The name of the sheet within the
|
||||
* spreadsheet file to render. If this argument is omitted, the
|
||||
* first sheet is rendered.
|
||||
* @returns A newly created helma.Chart instance.
|
||||
* @constructor
|
||||
* @author Tobi Schaefer
|
||||
*/
|
||||
helma.Chart = function(fpath, prefix, sheetName) {
|
||||
var JXLPKG = Packages.jxl.Workbook;
|
||||
var JXLPKGNAME = "jxl.jar";
|
||||
var JXLPKGURL = "http://www.andykhan.com/jexcelapi/";
|
||||
|
||||
var workbook, file;
|
||||
try {
|
||||
file = new java.io.File(fpath);
|
||||
workbook = JXLPKG.getWorkbook(file);
|
||||
} catch (e) {
|
||||
if (e instanceof TypeError == false)
|
||||
throw(e);
|
||||
throw("helma.Chart needs " + JXLPKGNAME +
|
||||
" in lib/ext or application directory " +
|
||||
"[" + JXLPKGURL + "]");
|
||||
}
|
||||
|
||||
var getCellStyle = function(c) {
|
||||
if (!c)
|
||||
return;
|
||||
var result = new Object();
|
||||
var format = c.getCellFormat();
|
||||
var font = format.getFont();
|
||||
if (font.getBoldWeight() > 400)
|
||||
result.bold = true;
|
||||
result.italic = font.isItalic();
|
||||
result.wrap = format.getWrap();
|
||||
var type = c.getType();
|
||||
var align = format.getAlignment().getDescription();
|
||||
if (align == "right" || type == "Number" || type == "Date")
|
||||
result.align = "right";
|
||||
else if (align == "centre")
|
||||
result.align = "center";
|
||||
return result;
|
||||
}
|
||||
|
||||
if (sheetName) {
|
||||
var sheet = workbook.getSheet(sheetName);
|
||||
} else {
|
||||
var sheet = workbook.getSheet(0);
|
||||
}
|
||||
if (!sheet)
|
||||
return;
|
||||
|
||||
prefix = prefix ? prefix + "_" : "chart_";
|
||||
|
||||
/**
|
||||
* Renders the Excel spreadsheet as XHTML table.
|
||||
*/
|
||||
this.render = function() {
|
||||
res.write('<table border="0" cellspacing="1" class="' +
|
||||
prefix + 'table">\n');
|
||||
|
||||
var rowBuf = [];
|
||||
var rows = sheet.getRows();
|
||||
var max = 0;
|
||||
for (var i=0; i<rows; i+=1) {
|
||||
var row = sheet.getRow(i);
|
||||
if (row.length > max)
|
||||
max = row.length;
|
||||
rowBuf.push(row);
|
||||
}
|
||||
|
||||
for (var i in rowBuf) {
|
||||
res.write('<tr class="' + prefix + 'row">\n');
|
||||
for (var n=0; n<max; n+=1) {
|
||||
if (n < rowBuf[i].length) {
|
||||
var c = rowBuf[i][n];
|
||||
var str = c.getContents();
|
||||
if (str)
|
||||
var style = getCellStyle(c);
|
||||
}
|
||||
res.write('<td class="' + prefix + 'cell"');
|
||||
if (style) {
|
||||
if (!style.wrap)
|
||||
res.write(' nowrap="nowrap"');
|
||||
if (style.align)
|
||||
res.write(' align="' + style.align + '"');
|
||||
res.write(">");
|
||||
if (style.bold)
|
||||
res.write("<b>");
|
||||
if (style.italic)
|
||||
res.write("<i>");
|
||||
}
|
||||
else
|
||||
res.write(">");
|
||||
res.write(str);
|
||||
if (style) {
|
||||
if (style.italic)
|
||||
res.write("</i>");
|
||||
if (style.bold)
|
||||
res.write("</b>");
|
||||
}
|
||||
res.write('</td>\n');
|
||||
}
|
||||
res.write('</tr>\n');
|
||||
}
|
||||
|
||||
res.write('</table>\n');
|
||||
workbook.close();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the spreadsheet as rendered XHTML table.
|
||||
* @returns The rendered spreadsheet table
|
||||
* @type String
|
||||
*/
|
||||
this.renderAsString = function() {
|
||||
res.push();
|
||||
this.render();
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
this.toString = function() {
|
||||
return "[helma.Chart " + file + "]";
|
||||
};
|
||||
|
||||
for (var i in this)
|
||||
this.dontEnum(i);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/** @ignore */
|
||||
helma.Chart.toString = function() {
|
||||
return "[helma.Chart]";
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A simple example for using helma.Chart that renders
|
||||
* the passed file as XHTML table to response.
|
||||
* @param {String} file The path to the Excel spreadsheet file
|
||||
*/
|
||||
helma.Chart.example = function(file) {
|
||||
// var file = "/path/to/file.xls";
|
||||
var chart = new helma.Chart(file);
|
||||
chart.render();
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
helma.lib = "Chart";
|
||||
helma.dontEnum(helma.lib);
|
||||
for (var i in helma[helma.lib])
|
||||
helma[helma.lib].dontEnum(i);
|
||||
for (var i in helma[helma.lib].prototype)
|
||||
helma[helma.lib].prototype.dontEnum(i);
|
||||
delete helma.lib;
|
396
modules/helma/Color.js
Normal file
396
modules/helma/Color.js
Normal file
|
@ -0,0 +1,396 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Color.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the helma.Chart prototype
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/helma/Color.js')
|
||||
*/
|
||||
|
||||
// take care of any dependencies
|
||||
app.addRepository("modules/core/String.js");
|
||||
|
||||
/**
|
||||
* Define the global namespace if not existing
|
||||
*/
|
||||
if (!global.helma) {
|
||||
global.helma = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of helma.Color.
|
||||
* @class Instances of this class provide methods for
|
||||
* converting HTML color names into their corresponding
|
||||
* RGB values and vice versa, or retrieving single RGB color values.
|
||||
* @param {Number|String} R Either the red fraction of the color,
|
||||
* or the name of the color.
|
||||
* @param {Number} G The green fraction
|
||||
* @param {Number} B The blue fraction
|
||||
* @returns A newly created helma.Color instance
|
||||
* @constructor
|
||||
*/
|
||||
helma.Color = function(R, G, B) {
|
||||
var value = null;
|
||||
var name = null;
|
||||
var hex = null;
|
||||
var rgb = null;
|
||||
|
||||
/**
|
||||
* Returns the decimal value of this color, or of a specified
|
||||
* color channel.
|
||||
* @param {String} channel An optional color channel which
|
||||
* decimal value should be returned. Must be either "red",
|
||||
* "green" or "blue". If no channel is specified this
|
||||
* method returns the decimal value of the color itself.
|
||||
* @returns The decimal value of this color or a single channel.
|
||||
* @type Number
|
||||
*/
|
||||
this.valueOf = function(channel) {
|
||||
if (channel) {
|
||||
if (!rgb) {
|
||||
var compose = function(n, bits) {
|
||||
var div = Math.pow(2, bits);
|
||||
remainder = n % div;
|
||||
return Math.floor(n/div);
|
||||
}
|
||||
var remainder = value;
|
||||
rgb = {
|
||||
red: compose(remainder, 16),
|
||||
green: compose(remainder, 8),
|
||||
blue: compose(remainder, 0)
|
||||
};
|
||||
}
|
||||
return rgb[channel];
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the hexidecimal value of this color (without
|
||||
* a leading hash sign).
|
||||
* @returns The hexidecimal value of this color
|
||||
* @type String
|
||||
*/
|
||||
this.toString = function() {
|
||||
if (!value)
|
||||
return null;
|
||||
if (!hex)
|
||||
hex = value.toString(16).pad("0", 6, String.LEFT);
|
||||
return hex;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the trivial name of this color
|
||||
* @returns The trivial name of this color
|
||||
* @type String
|
||||
*/
|
||||
this.getName = function() {
|
||||
return helma.Color.COLORVALUES[value];
|
||||
};
|
||||
|
||||
/**
|
||||
* Main constructor body
|
||||
*/
|
||||
if (arguments.length % 2 == 0)
|
||||
throw("Insufficient arguments for creating Color");
|
||||
if (arguments.length == 1) {
|
||||
if (R.constructor == Number) {
|
||||
value = R;
|
||||
} else if (R.constructor == String) {
|
||||
R = R.toLowerCase();
|
||||
if (helma.Color.COLORNAMES[R]) {
|
||||
this.name = R;
|
||||
value = helma.Color.COLORNAMES[R];
|
||||
} else {
|
||||
if (R.startsWith("#")) {
|
||||
R = R.substring(1);
|
||||
}
|
||||
value = parseInt(R, 16);
|
||||
this.name = helma.Color.COLORVALUES[value];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
value = R * Math.pow(2, 16) + G * Math.pow(2, 8) + B;
|
||||
}
|
||||
|
||||
if (value == null || isNaN(value))
|
||||
throw("helma.Color: invalid argument " + R);
|
||||
|
||||
for (var i in this)
|
||||
this.dontEnum(i);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new helma.Color instance based on a color name.
|
||||
* @param {String} name The color name (eg. "darkseagreen")
|
||||
* @returns An instance of helma.Color representing the color specified
|
||||
* @type helma.Color
|
||||
*/
|
||||
helma.Color.fromName = function(name) {
|
||||
var value = helma.Color.COLORNAMES[name.toLowerCase()];
|
||||
return new helma.Color(value || 0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new helma.Color instance based on a HSL color
|
||||
* representation. This method is adapted from the HSLtoRGB
|
||||
* conversion method as described at
|
||||
* <a href="http://www1.tip.nl/~t876506/ColorDesign.html#hr">http://www1.tip.nl/~t876506/ColorDesign.html#hr</a>.
|
||||
* @param {Number} H The hue fraction of the color definition
|
||||
* @param {Number} S The saturation fraction
|
||||
* @param {Number} L The lightness fraction
|
||||
* @returns An instance of helma.Color representing the corresponding
|
||||
* RGB color definition.
|
||||
* @type helma.Color
|
||||
*/
|
||||
helma.Color.fromHsl = function(H,S,L) {
|
||||
function H1(H,S,L) {
|
||||
var R = 1; var G = 6*H; var B = 0;
|
||||
G = G*S + 1 - S; B = B*S + 1 - S;
|
||||
R = R*L; G = G*L; B = B*L;
|
||||
return [R,G,B];
|
||||
}
|
||||
|
||||
function H2(H,S,L) {
|
||||
var R = 1-6*(H - 1/6); var G = 1; var B = 0;
|
||||
R = R*S + 1 - S; B = B*S + 1 - S;
|
||||
R = R*L; G = G*L; B = B*L;
|
||||
return [R,G,B];
|
||||
}
|
||||
|
||||
function H3(H,S,L) {
|
||||
var R = 0; var G = 1; var B = 6*(H - 1/3);
|
||||
R = R*S + 1 - S; B = B*S + 1 - S;
|
||||
R = R*L; G = G*L; B = B*L
|
||||
return [R,G,B];
|
||||
}
|
||||
|
||||
function H4(H,S,L) {
|
||||
var R = 0; var G = 1-6*(H - 1/2); var B = 1;
|
||||
R = R*S + 1 - S; G = G*S + 1 - S;
|
||||
R = R*L; G = G*L; B = B*L;
|
||||
return [R,G,B];
|
||||
}
|
||||
|
||||
function H5(H,S,L) {
|
||||
var R = 6*(H - 2/3); var G = 0; var B = 1;
|
||||
R = R*S + 1 - S; G = G*S + 1 - S;
|
||||
R = R*L; G = G*L; B = B*L;
|
||||
return [R,G,B];
|
||||
}
|
||||
|
||||
function H6(H,S,L) {
|
||||
var R = 1; var G = 0; var B = 1-6*(H - 5/6);
|
||||
G = G*S + 1 - S; B = B*S + 1 - S;
|
||||
R = R*L; G = G*L; B = B*L;
|
||||
return [R,G,B];
|
||||
}
|
||||
|
||||
// H [0-1] is divided into 6 equal sectors.
|
||||
// From within each sector the proper conversion function is called.
|
||||
var rgb;
|
||||
if (H < 1/6) rgb = H1(H,S,L);
|
||||
else if (H < 1/3) rgb = H2(H,S,L);
|
||||
else if (H < 1/2) rgb = H3(H,S,L);
|
||||
else if (H < 2/3) rgb = H4(H,S,L);
|
||||
else if (H < 5/6) rgb = H5(H,S,L);
|
||||
else rgb = H6(H,S,L);
|
||||
|
||||
return new helma.Color(
|
||||
Math.round(rgb[0]*255),
|
||||
Math.round(rgb[1]*255),
|
||||
Math.round(rgb[2]*255)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Contains the hexadecimal values of named colors.
|
||||
* @type Object
|
||||
* @final
|
||||
*/
|
||||
helma.Color.COLORNAMES = {
|
||||
black: 0x000000,
|
||||
maroon: 0x800000,
|
||||
green: 0x008000,
|
||||
olive: 0x808000,
|
||||
navy: 0x000080,
|
||||
purple: 0x800080,
|
||||
teal: 0x008080,
|
||||
silver: 0xc0c0c0,
|
||||
gray: 0x808080,
|
||||
red: 0xff0000,
|
||||
lime: 0x00ff00,
|
||||
yellow: 0xffff00,
|
||||
blue: 0x0000ff,
|
||||
fuchsia: 0xff00ff,
|
||||
aqua: 0x00ffff,
|
||||
white: 0xffffff,
|
||||
aliceblue: 0xf0f8ff,
|
||||
antiquewhite: 0xfaebd7,
|
||||
aquamarine: 0x7fffd4,
|
||||
azure: 0xf0ffff,
|
||||
beige: 0xf5f5dc,
|
||||
blueviolet: 0x8a2be2,
|
||||
brown: 0xa52a2a,
|
||||
burlywood: 0xdeb887,
|
||||
cadetblue: 0x5f9ea0,
|
||||
chartreuse: 0x7fff00,
|
||||
chocolate: 0xd2691e,
|
||||
coral: 0xff7f50,
|
||||
cornflowerblue: 0x6495ed,
|
||||
cornsilk: 0xfff8dc,
|
||||
crimson: 0xdc143c,
|
||||
darkblue: 0x00008b,
|
||||
darkcyan: 0x008b8b,
|
||||
darkgoldenrod: 0xb8860b,
|
||||
darkgray: 0xa9a9a9,
|
||||
darkgreen: 0x006400,
|
||||
darkkhaki: 0xbdb76b,
|
||||
darkmagenta: 0x8b008b,
|
||||
darkolivegreen: 0x556b2f,
|
||||
darkorange: 0xff8c00,
|
||||
darkorchid: 0x9932cc,
|
||||
darkred: 0x8b0000,
|
||||
darksalmon: 0xe9967a,
|
||||
darkseagreen: 0x8fbc8f,
|
||||
darkslateblue: 0x483d8b,
|
||||
darkslategray: 0x2f4f4f,
|
||||
darkturquoise: 0x00ced1,
|
||||
darkviolet: 0x9400d3,
|
||||
deeppink: 0xff1493,
|
||||
deepskyblue: 0x00bfff,
|
||||
dimgray: 0x696969,
|
||||
dodgerblue: 0x1e90ff,
|
||||
firebrick: 0xb22222,
|
||||
floralwhite: 0xfffaf0,
|
||||
forestgreen: 0x228b22,
|
||||
gainsboro: 0xdcdcdc,
|
||||
ghostwhite: 0xf8f8ff,
|
||||
gold: 0xffd700,
|
||||
goldenrod: 0xdaa520,
|
||||
greenyellow: 0xadff2f,
|
||||
honeydew: 0xf0fff0,
|
||||
hotpink: 0xff69b4,
|
||||
indianred: 0xcd5c5c,
|
||||
indigo: 0x4b0082,
|
||||
ivory: 0xfffff0,
|
||||
khaki: 0xf0e68c,
|
||||
lavender: 0xe6e6fa,
|
||||
lavenderblush: 0xfff0f5,
|
||||
lawngreen: 0x7cfc00,
|
||||
lemonchiffon: 0xfffacd,
|
||||
lightblue: 0xadd8e6,
|
||||
lightcoral: 0xf08080,
|
||||
lightcyan: 0xe0ffff,
|
||||
lightgoldenrodyellow: 0xfafad2,
|
||||
lightgreen: 0x90ee90,
|
||||
lightgrey: 0xd3d3d3,
|
||||
lightpink: 0xffb6c1,
|
||||
lightsalmon: 0xffa07a,
|
||||
lightseagreen: 0x20b2aa,
|
||||
lightskyblue: 0x87cefa,
|
||||
lightslategray: 0x778899,
|
||||
lightsteelblue: 0xb0c4de,
|
||||
lightyellow: 0xffffe0,
|
||||
limegreen: 0x32cd32,
|
||||
linen: 0xfaf0e6,
|
||||
mediumaquamarine: 0x66cdaa,
|
||||
mediumblue: 0x0000cd,
|
||||
mediumorchid: 0xba55d3,
|
||||
mediumpurple: 0x9370db,
|
||||
mediumseagreen: 0x3cb371,
|
||||
mediumslateblue: 0x7b68ee,
|
||||
mediumspringgreen: 0x00fa9a,
|
||||
mediumturquoise: 0x48d1cc,
|
||||
mediumvioletred: 0xc71585,
|
||||
midnightblue: 0x191970,
|
||||
mintcream: 0xf5fffa,
|
||||
mistyrose: 0xffe4e1,
|
||||
moccasin: 0xffe4b5,
|
||||
navajowhite: 0xffdead,
|
||||
oldlace: 0xfdf5e6,
|
||||
olivedrab: 0x6b8e23,
|
||||
orange: 0xffa500,
|
||||
orangered: 0xff4500,
|
||||
orchid: 0xda70d6,
|
||||
palegoldenrod: 0xeee8aa,
|
||||
palegreen: 0x98fb98,
|
||||
paleturquoise: 0xafeeee,
|
||||
palevioletred: 0xdb7093,
|
||||
papayawhip: 0xffefd5,
|
||||
peachpuff: 0xffdab9,
|
||||
peru: 0xcd853f,
|
||||
pink: 0xffc0cb,
|
||||
plum: 0xdda0dd,
|
||||
powderblue: 0xb0e0e6,
|
||||
rosybrown: 0xbc8f8f,
|
||||
royalblue: 0x4169e1,
|
||||
saddlebrown: 0x8b4513,
|
||||
salmon: 0xfa8072,
|
||||
sandybrown: 0xf4a460,
|
||||
seagreen: 0x2e8b57,
|
||||
seashell: 0xfff5ee,
|
||||
sienna: 0xa0522d,
|
||||
skyblue: 0x87ceeb,
|
||||
slateblue: 0x6a5acd,
|
||||
slategray: 0x708090,
|
||||
snow: 0xfffafa,
|
||||
springgreen: 0x00ff7f,
|
||||
steelblue: 0x4682b4,
|
||||
tan: 0xd2b48c,
|
||||
thistle: 0xd8bfd8,
|
||||
tomato: 0xff6347,
|
||||
turquoise: 0x40e0d0,
|
||||
violet: 0xee82ee,
|
||||
wheat: 0xf5deb3,
|
||||
whitesmoke: 0xf5f5f5,
|
||||
yellowgreen: 0x9acd32
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Contains the color names for specific hex values
|
||||
* @type Object
|
||||
* @final
|
||||
*/
|
||||
helma.Color.COLORVALUES = {};
|
||||
|
||||
for (var i in helma.Color.COLORNAMES) {
|
||||
helma.Color.COLORVALUES[helma.Color.COLORNAMES[i]] = i;
|
||||
}
|
||||
|
||||
|
||||
/** @ignore */
|
||||
helma.Color.toString = function() {
|
||||
return "[helma.Color]";
|
||||
};
|
||||
|
||||
|
||||
helma.lib = "Color";
|
||||
helma.dontEnum(helma.lib);
|
||||
for (var i in helma[helma.lib])
|
||||
helma[helma.lib].dontEnum(i);
|
||||
for (var i in helma[helma.lib].prototype)
|
||||
helma[helma.lib].prototype.dontEnum(i);
|
||||
delete helma.lib;
|
341
modules/helma/Database.js
Normal file
341
modules/helma/Database.js
Normal file
|
@ -0,0 +1,341 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Database.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Properties and methods of the helma.Database prototype.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/helma/Database.js')
|
||||
*/
|
||||
|
||||
if (!global.helma) {
|
||||
global.helma = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for Database objects, providing access through relational
|
||||
* databases through JDBC. It is usually simpler to use one of the factory
|
||||
* methods {@link #createInstance} or {@link #getInstance}.
|
||||
* @class <p>This class provides access to a relational database through JDBC.
|
||||
* There are two convenient ways to create instances of this class.</p>
|
||||
*
|
||||
* <p>The first is to use {@link #getInstance helma.Database.getInstance()}
|
||||
* to obtain a connection to a DB that is defined in the application's
|
||||
* db.properties and managed by Helma. The second way is to define and create
|
||||
* a database connection locally using
|
||||
* {@link #createInstance helma.Database.createInstance()} and passing it
|
||||
* all necessary parameters.</p>
|
||||
*
|
||||
* <p>This class provides two ways of interaction:
|
||||
* The {@link #query} method allows to issue SQL queries, returning a result set.
|
||||
* The {@link #execute} provides a way to issue SQL statements that do not
|
||||
* return a result set.</p>
|
||||
*
|
||||
* <p>Database connections allocated by this class are be managed and eventually
|
||||
* disposed by Helma.</p>
|
||||
*
|
||||
* @param {DbSource} source instance of a helma.objectmodel.db.DbSource
|
||||
* @constructor
|
||||
*/
|
||||
helma.Database = function(source) {
|
||||
var Types = java.sql.Types;
|
||||
var DbSource = Packages.helma.objectmodel.db.DbSource;
|
||||
|
||||
if (typeof(source) == "string")
|
||||
source = app.getDbSource(source);
|
||||
if (!(source instanceof DbSource))
|
||||
throw "helma.Database requires a helma.objectmodel.db.DbSource argument";
|
||||
|
||||
/**
|
||||
* Get the java.sql.Connection for this Database instance. This can be used
|
||||
* to operate on the connection directly, without going through the helma.Database
|
||||
* class.
|
||||
* @return {java.sql.Connection} the JDBC connection
|
||||
*/
|
||||
this.getConnection = function() {
|
||||
return source.getConnection();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the lower case name of the underlying database product.
|
||||
* @return {String} the name of the DB product
|
||||
*/
|
||||
this.getProductName = function() {
|
||||
return source.getConnection().getMetaData().getDatabaseProductName().toLowerCase();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if this is an Oracle database.
|
||||
* @return {boolean} true if this is an Oracle database.
|
||||
*/
|
||||
this.isOracle = function() {
|
||||
return source.isOracle();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if this is a MySQL database.
|
||||
* @return {boolean} true if this is an MySQL database.
|
||||
*/
|
||||
this.isMySql = function() {
|
||||
return source.isMySQL();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if this is a PostgreSQL database.
|
||||
* @return {boolean} true if this is a PostgreSQL database.
|
||||
*/
|
||||
this.isPostgreSql = function() {
|
||||
return source.isPostgreSQL();
|
||||
};
|
||||
|
||||
/**
|
||||
* Executes the given SQL statement. The result set is returned
|
||||
* as JavaScript Array containing a JavaScript Object for each result.
|
||||
* @param {String} sql an SQL query statement
|
||||
* @return {Array} an Array containing the result set
|
||||
*/
|
||||
this.query = function(sql) {
|
||||
var isLogSqlEnabled = (getProperty("logSQL", "false").toLowerCase() == "true");
|
||||
var logTimeStart = isLogSqlEnabled ? java.lang.System.currentTimeMillis() : 0;
|
||||
var connection = source.getConnection();
|
||||
connection.setReadOnly(true);
|
||||
var statement = connection.createStatement();
|
||||
var resultSet = statement.executeQuery(sql);
|
||||
var metaData = resultSet.getMetaData();
|
||||
var max = metaData.getColumnCount();
|
||||
var types = [];
|
||||
for (var i=1; i <= max; i++) {
|
||||
types[i] = metaData.getColumnType(i);
|
||||
}
|
||||
var result = [];
|
||||
while (resultSet.next()) {
|
||||
var row = {}
|
||||
for (var i=1; i<=max; i+=1) {
|
||||
switch (types[i]) {
|
||||
case Types.BIT:
|
||||
case Types.BOOLEAN:
|
||||
row[metaData.getColumnLabel(i)] = resultSet.getBoolean(i);
|
||||
break;
|
||||
case Types.TINYINT:
|
||||
case Types.BIGINT:
|
||||
case Types.SMALLINT:
|
||||
case Types.INTEGER:
|
||||
row[metaData.getColumnLabel(i)] = resultSet.getLong(i);
|
||||
break;
|
||||
case Types.REAL:
|
||||
case Types.FLOAT:
|
||||
case Types.DOUBLE:
|
||||
case Types.DECIMAL:
|
||||
case Types.NUMERIC:
|
||||
row[metaData.getColumnLabel(i)] = resultSet.getDouble(i);
|
||||
break;
|
||||
case Types.VARBINARY:
|
||||
case Types.BINARY:
|
||||
case Types.LONGVARBINARY:
|
||||
case Types.LONGVARCHAR:
|
||||
case Types.CHAR:
|
||||
case Types.VARCHAR:
|
||||
case Types.CLOB:
|
||||
case Types.OTHER:
|
||||
row[metaData.getColumnLabel(i)] = resultSet.getString(i);
|
||||
break;
|
||||
case Types.DATE:
|
||||
case Types.TIME:
|
||||
case Types.TIMESTAMP:
|
||||
row[metaData.getColumnLabel(i)] = resultSet.getTimestamp(i);
|
||||
break;
|
||||
case Types.NULL:
|
||||
row[metaData.getColumnLabel(i)] = null;
|
||||
break;
|
||||
default:
|
||||
row[metaData.getColumnLabel(i)] = resultSet.getString(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
result[result.length] = row;
|
||||
}
|
||||
var logTimeStop = isLogSqlEnabled ? java.lang.System.currentTimeMillis() : 0;
|
||||
if (isLogSqlEnabled) {
|
||||
var tableName = metaData.getColumnCount() > 0 ? metaData.getTableName(1) : null;
|
||||
app.getLogger("helma." + app.name + ".sql").info("SQL DIRECT_QUERY " + (tableName || "-") + " " + (logTimeStop - logTimeStart) + ": " + sql);
|
||||
}
|
||||
try {
|
||||
statement.close();
|
||||
resultSet.close();
|
||||
} catch (error) {
|
||||
// ignore
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Executes the given SQL statement, which may be an INSERT, UPDATE,
|
||||
* or DELETE statement or an SQL statement that returns nothing,
|
||||
* such as an SQL data definition statement. The return value is an integer that
|
||||
* indicates the number of rows that were affected by the statement.
|
||||
* @param {String} sql an SQL statement
|
||||
* @return {int} either the row count for INSERT, UPDATE or
|
||||
* DELETE statements, or 0 for SQL statements that return nothing
|
||||
*/
|
||||
this.execute = function(sql) {
|
||||
var isLogSqlEnabled = (getProperty("logSQL", "false").toLowerCase() == "true");
|
||||
var logTimeStart = isLogSqlEnabled ? java.lang.System.currentTimeMillis() : 0;
|
||||
var connection = source.getConnection();
|
||||
connection.setReadOnly(false);
|
||||
var statement = connection.createStatement();
|
||||
var result;
|
||||
try {
|
||||
result = statement.executeUpdate(sql);
|
||||
} finally {
|
||||
try {
|
||||
statement.close();
|
||||
} catch (error) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
var logTimeStop = isLogSqlEnabled ? java.lang.System.currentTimeMillis() : 0;
|
||||
if (isLogSqlEnabled) {
|
||||
app.getLogger("helma." + app.name + ".sql").info("SQL DIRECT_EXECUTE - " + (logTimeStop - logTimeStart) + ": " + sql);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the name of the Helma DbSource object.
|
||||
* @return {String} the DbSource name
|
||||
*/
|
||||
this.getName = function() {
|
||||
return source.getName();
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the name of the JDBC driver used by this Database instance.
|
||||
* @return {String} the JDBC driver name
|
||||
*/
|
||||
this.getDriverName = function() {
|
||||
return source.getDriverName();
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
this.toString = function() {
|
||||
return "[helma.Database " + this.getName() + "]";
|
||||
};
|
||||
|
||||
for (var i in this)
|
||||
this.dontEnum(i);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new Database instance using the given parameters.
|
||||
* <p>Some of the parameters support shortcuts for known database products.
|
||||
* The <code>url</code> parameter recognizes the values "mysql", "oracle" and
|
||||
* "postgresql". For those databases, it is also possible to pass just
|
||||
* <code>hostname</code> or <code>hostname:port</code> as <code>url</code>
|
||||
* parameters instead of the full JDBC URL.</p>
|
||||
* @param {String} driver the class name of the JDBC driver. As
|
||||
* shortcuts, the values "mysql", "oracle" and "postgresql" are
|
||||
* recognized.
|
||||
* @param {String} url the JDBC URL.
|
||||
* @param {String} name the name of the database to use
|
||||
* @param {String} user the the username
|
||||
* @param {String} password the password
|
||||
* @return {helma.Database} a helma.Database instance
|
||||
*/
|
||||
helma.Database.createInstance = function(driver, url, name, user, password) {
|
||||
var DbSource = Packages.helma.objectmodel.db.DbSource;
|
||||
|
||||
if (!driver || !url || !name)
|
||||
throw("Insufficient arguments to create helma.db.Connection");
|
||||
if (typeof password != "string")
|
||||
password = "";
|
||||
|
||||
var MYSQL = "mysql";
|
||||
var ORACLE = "oracle";
|
||||
var POSTGRESQL = "postgresql";
|
||||
var JDBC = "jdbc:";
|
||||
var DRIVER_MYSQL = "com.mysql.jdbc.Driver";
|
||||
var DRIVER_ORACLE = "oracle.jdbc.driver.OracleDriver";
|
||||
var DRIVER_POSTGRESQL = "org.postgresql.Driver";
|
||||
|
||||
if (driver == MYSQL) {
|
||||
driver = DRIVER_MYSQL;
|
||||
if (url.indexOf(JDBC) != 0)
|
||||
url = "jdbc:mysql://" + url + "/" + name;
|
||||
} else if (driver == ORACLE) {
|
||||
driver = DRIVER_ORACLE;
|
||||
if (url.indexOf(JDBC) != 0)
|
||||
url = "jdbc:oracle:thin:@" + url + ":" + name;
|
||||
} else if (driver == POSTGRESQL) {
|
||||
driver = DRIVER_POSTGRESQL;
|
||||
if (url.indexOf(JDBC) != 0)
|
||||
url = "jdbc:postgresql://" + url + "/" + name;
|
||||
}
|
||||
var props = new Packages.helma.util.ResourceProperties();
|
||||
props.put(name + ".url", url);
|
||||
props.put(name + ".driver", driver);
|
||||
if (user) {
|
||||
props.put(name + ".user", user)
|
||||
}
|
||||
if (password) {
|
||||
props.put(name + ".password", password);
|
||||
}
|
||||
return new helma.Database(new DbSource(name, props));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Database instance using the Database source defined in the
|
||||
* application's db.properties file with the given name.
|
||||
* @param {String} name the name of the DB source as defined in db.properties
|
||||
* @return {helma.Database} a helma.Database instance
|
||||
*/
|
||||
helma.Database.getInstance = function(name) {
|
||||
return new helma.Database(app.getDbSource(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
helma.Database.toString = function() {
|
||||
return "[helma.Database]";
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
helma.Database.example = function() {
|
||||
var type = "mysql";
|
||||
var host = "localhost";
|
||||
var user = "root";
|
||||
var pw = "";
|
||||
var name = "mysql";
|
||||
var db = new helma.Database(type, host, user, pw, name);
|
||||
var result = db.query("select count(*) from db");
|
||||
res.write(result.toSource());
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
helma.lib = "Database";
|
||||
helma.dontEnum(helma.lib);
|
||||
for (var i in helma[helma.lib])
|
||||
helma[helma.lib].dontEnum(i);
|
||||
for (var i in helma[helma.lib].prototype)
|
||||
helma[helma.lib].prototype.dontEnum(i);
|
||||
delete helma.lib;
|
760
modules/helma/File.js
Normal file
760
modules/helma/File.js
Normal file
|
@ -0,0 +1,760 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2007 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: File.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Default properties and methods of the File prototype.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/helma/File.js')
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Define the global namespace if not existing
|
||||
*/
|
||||
if (!global.helma) {
|
||||
global.helma = {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for File objects, providing read and
|
||||
* write access to the file system.
|
||||
* @class This class represents a local file or directory
|
||||
* @param {String} path as String, can be either absolute or relative to the helma home directory
|
||||
* @constructor
|
||||
*/
|
||||
helma.File = function(path) {
|
||||
var BufferedReader = java.io.BufferedReader;
|
||||
var File = java.io.File;
|
||||
var Writer = java.io.Writer;
|
||||
var FileReader = java.io.FileReader;
|
||||
var PrintWriter = java.io.PrintWriter;
|
||||
var FileOutputStream = java.io.FileOutputStream;
|
||||
var OutputStreamWriter = java.io.OutputStreamWriter;
|
||||
var FileInputStream = java.io.FileInputStream;
|
||||
var InputStreamReader = java.io.InputStreamReader;
|
||||
var EOFException = java.io.EOFException;
|
||||
var IllegalStateException = java.lang.IllegalStateException;
|
||||
var IllegalArgumentException = java.lang.IllegalArgumentException
|
||||
|
||||
var self = this;
|
||||
|
||||
var file;
|
||||
try {
|
||||
// immediately convert to absolute path - java.io.File is
|
||||
// incredibly stupid when dealing with relative file names
|
||||
if (arguments.length > 1)
|
||||
file = new File(path, arguments[1]).getAbsoluteFile();
|
||||
else
|
||||
file = new File(path).getAbsoluteFile();
|
||||
} catch (e) {
|
||||
throw(e);
|
||||
}
|
||||
|
||||
var readerWriter;
|
||||
var atEOF = false;
|
||||
var lastLine = null;
|
||||
|
||||
var setError = function(e) {
|
||||
self.lastError = e;
|
||||
};
|
||||
|
||||
this.lastError = null;
|
||||
|
||||
/** @ignore */
|
||||
this.toString = function() {
|
||||
return file.toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the name of the file or directory represented by this File object.
|
||||
* <br /><br />
|
||||
* This is just the last name in the pathname's name sequence.
|
||||
* If the pathname's name sequence is empty, then the empty
|
||||
* string is returned.
|
||||
*
|
||||
* @returns String containing the name of the file or directory
|
||||
* @type String
|
||||
*/
|
||||
this.getName = function() {
|
||||
var name = file.getName();
|
||||
return (name == null ? "" : name);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the file represented by this File object
|
||||
* is currently open.
|
||||
*
|
||||
* @returns Boolean
|
||||
* @type Boolean
|
||||
*/
|
||||
this.isOpened = function() {
|
||||
return (readerWriter != null);
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens the file represented by this File object. If the file exists,
|
||||
* it is used for reading, otherwise it is opened for writing.
|
||||
* If the encoding argument is specified, it is used to read or write
|
||||
* the file. Otherwise, the platform's default encoding is used.
|
||||
*
|
||||
* @param {Object} options an optional argument holder object.
|
||||
* The following options are supported:
|
||||
* <ul><li>charset name of encoding to use for reading or writing</li>
|
||||
* <li>append whether to append to the file if it exists</li></ul>
|
||||
* @returns Boolean true if the operation succeeded
|
||||
* @type Boolean
|
||||
*/
|
||||
this.open = function(options) {
|
||||
if (self.isOpened()) {
|
||||
setError(new IllegalStateException("File already open"));
|
||||
return false;
|
||||
}
|
||||
// We assume that the BufferedReader and PrintWriter creation
|
||||
// cannot fail except if the FileReader/FileWriter fails.
|
||||
// Otherwise we have an open file until the reader/writer
|
||||
// get garbage collected.
|
||||
var charset = options && options.charset;
|
||||
var append = options && options.append;
|
||||
try {
|
||||
if (file.exists() && !append) {
|
||||
if (charset) {
|
||||
readerWriter = new BufferedReader(
|
||||
new InputStreamReader(new FileInputStream(file), charset));
|
||||
} else {
|
||||
readerWriter = new BufferedReader(new FileReader(file));
|
||||
}
|
||||
} else {
|
||||
if (append && charset) {
|
||||
readerWriter = new PrintWriter(
|
||||
new OutputStreamWriter(new FileOutputStream(file, true), charset));
|
||||
} else if (append) {
|
||||
readerWriter = new PrintWriter(
|
||||
new OutputStreamWriter(new FileOutputStream(file, true)));
|
||||
} else if (charset) {
|
||||
readerWriter = new PrintWriter(file, charset);
|
||||
} else {
|
||||
readerWriter = new PrintWriter(file);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
setError(e);
|
||||
return false;
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tests whether the file or directory represented by this File object exists.
|
||||
*
|
||||
* @returns Boolean true if the file or directory exists; false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
this.exists = function() {
|
||||
return file.exists();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the pathname string of this File object's parent directory.
|
||||
*
|
||||
* @returns String containing the pathname of the parent directory
|
||||
* @type String
|
||||
*/
|
||||
this.getParent = function() {
|
||||
if (!file.getParent())
|
||||
return null;
|
||||
return new helma.File(file.getParent());
|
||||
};
|
||||
|
||||
/**
|
||||
* This methods reads characters until an end of line/file is encountered
|
||||
* then returns the string for these characters (without any end of line
|
||||
* character).
|
||||
*
|
||||
* @returns String of the next unread line in the file
|
||||
* @type String
|
||||
*/
|
||||
this.readln = function() {
|
||||
if (!self.isOpened()) {
|
||||
setError(new IllegalStateException("File not opened"));
|
||||
return null;
|
||||
}
|
||||
if (!(readerWriter instanceof BufferedReader)) {
|
||||
setError(new IllegalStateException("File not opened for reading"));
|
||||
return null;
|
||||
}
|
||||
if (atEOF) {
|
||||
setError(new EOFException());
|
||||
return null;
|
||||
}
|
||||
if (lastLine != null) {
|
||||
var line = lastLine;
|
||||
lastLine = null;
|
||||
return line;
|
||||
}
|
||||
var reader = readerWriter;
|
||||
// Here lastLine is null, return a new line
|
||||
try {
|
||||
var line = readerWriter.readLine();
|
||||
if (line == null) {
|
||||
atEOF = true;
|
||||
setError(new EOFException());
|
||||
}
|
||||
return line;
|
||||
} catch (e) {
|
||||
setError(e);
|
||||
return null;
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Appends a string to the file represented by this File object.
|
||||
*
|
||||
* @param {String} what as String, to be written to the file
|
||||
* @returns Boolean
|
||||
* @type Boolean
|
||||
* @see #writeln
|
||||
*/
|
||||
this.write = function(what) {
|
||||
if (!self.isOpened()) {
|
||||
setError(new IllegalStateException("File not opened"));
|
||||
return false;
|
||||
}
|
||||
if (!(readerWriter instanceof PrintWriter)) {
|
||||
setError(new IllegalStateException("File not opened for writing"));
|
||||
return false;
|
||||
}
|
||||
if (what != null) {
|
||||
readerWriter.print(what.toString());
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Appends a string with a platform specific end of
|
||||
* line to the file represented by this File object.
|
||||
*
|
||||
* @param {String} what as String, to be written to the file
|
||||
* @returns Boolean
|
||||
* @type Boolean
|
||||
* @see #write
|
||||
*/
|
||||
this.writeln = function(what) {
|
||||
if (self.write(what)) {
|
||||
readerWriter.println();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tests whether this File object's pathname is absolute.
|
||||
* <br /><br />
|
||||
* The definition of absolute pathname is system dependent.
|
||||
* On UNIX systems, a pathname is absolute if its prefix is "/".
|
||||
* On Microsoft Windows systems, a pathname is absolute if its prefix
|
||||
* is a drive specifier followed by "\\", or if its prefix is "\\".
|
||||
*
|
||||
* @returns Boolean if this abstract pathname is absolute, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
this.isAbsolute = function() {
|
||||
return file.isAbsolute();
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes the file or directory represented by this File object.
|
||||
*
|
||||
* @returns Boolean
|
||||
* @type Boolean
|
||||
*/
|
||||
this.remove = function() {
|
||||
if (self.isOpened()) {
|
||||
setError(new IllegalStateException("An openened file cannot be removed"));
|
||||
return false;
|
||||
}
|
||||
return file["delete"]();
|
||||
};
|
||||
|
||||
/**
|
||||
* List of all files within the directory represented by this File object.
|
||||
* <br /><br />
|
||||
* You may pass a RegExp Pattern to return just files matching this pattern.
|
||||
* <br /><br />
|
||||
* Example: var xmlFiles = dir.list(/.*\.xml/);
|
||||
*
|
||||
* @param {RegExp} pattern as RegExp, optional pattern to test each file name against
|
||||
* @returns Array the list of file names
|
||||
* @type Array
|
||||
*/
|
||||
this.list = function(pattern) {
|
||||
if (self.isOpened())
|
||||
return null;
|
||||
if (!file.isDirectory())
|
||||
return null;
|
||||
if (pattern) {
|
||||
var fileList = file.list();
|
||||
var result = [];
|
||||
for (var i in fileList) {
|
||||
if (pattern.test(fileList[i]))
|
||||
result.push(fileList[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return file.list();
|
||||
};
|
||||
|
||||
/**
|
||||
* Purges the content of the file represented by this File object.
|
||||
*
|
||||
* @returns Boolean
|
||||
* @type Boolean
|
||||
*/
|
||||
this.flush = function() {
|
||||
if (!self.isOpened()) {
|
||||
setError(new IllegalStateException("File not opened"));
|
||||
return false;
|
||||
}
|
||||
if (readerWriter instanceof Writer) {
|
||||
try {
|
||||
readerWriter.flush();
|
||||
} catch (e) {
|
||||
setError(e);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
setError(new IllegalStateException("File not opened for write"));
|
||||
return false; // not supported by reader
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Closes the file represented by this File object.
|
||||
*
|
||||
* @returns Boolean
|
||||
* @type Boolean
|
||||
*/
|
||||
this.close = function() {
|
||||
if (!self.isOpened())
|
||||
return false;
|
||||
try {
|
||||
atEOF = false;
|
||||
lastLine = null;
|
||||
readerWriter.close();
|
||||
readerWriter = null;
|
||||
return true;
|
||||
} catch (e) {
|
||||
setError(e);
|
||||
readerWriter = null;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the pathname string of this File object.
|
||||
* <br /><br />
|
||||
* The resulting string uses the default name-separator character
|
||||
* to separate the names in the name sequence.
|
||||
*
|
||||
* @returns String of this file's pathname
|
||||
* @type String
|
||||
*/
|
||||
this.getPath = function() {
|
||||
var path = file.getPath();
|
||||
return (path == null ? "" : path);
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains the last error that occured, if any.
|
||||
* @returns String
|
||||
* @type String
|
||||
* @see #clearError
|
||||
*/
|
||||
this.error = function() {
|
||||
if (this.lastError == null) {
|
||||
return "";
|
||||
} else {
|
||||
var exceptionName = this.lastError.getClass().getName();
|
||||
var l = exceptionName.lastIndexOf(".");
|
||||
if (l > 0)
|
||||
exceptionName = exceptionName.substring(l + 1);
|
||||
return exceptionName + ": " + this.lastError.getMessage();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears any error message that may otherwise be returned by the error method.
|
||||
*
|
||||
* @see #error
|
||||
*/
|
||||
this.clearError = function() {
|
||||
this.lastError = null;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tests whether the application can read the file
|
||||
* represented by this File object.
|
||||
*
|
||||
* @returns Boolean true if the file exists and can be read; false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
this.canRead = function() {
|
||||
return file.canRead();
|
||||
};
|
||||
|
||||
/**
|
||||
* Tests whether the file represented by this File object is writable.
|
||||
*
|
||||
* @returns Boolean true if the file exists and can be modified; false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
this.canWrite = function() {
|
||||
return file.canWrite();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the absolute pathname string of this file.
|
||||
* <br /><br />
|
||||
* If this File object's pathname is already absolute, then the pathname
|
||||
* string is simply returned as if by the getPath() method. If this
|
||||
* abstract pathname is the empty abstract pathname then the pathname
|
||||
* string of the current user directory, which is named by the system
|
||||
* property user.dir, is returned. Otherwise this pathname is resolved
|
||||
* in a system-dependent way. On UNIX systems, a relative pathname is
|
||||
* made absolute by resolving it against the current user directory.
|
||||
* On Microsoft Windows systems, a relative pathname is made absolute
|
||||
* by resolving it against the current directory of the drive named by
|
||||
* the pathname, if any; if not, it is resolved against the current user
|
||||
* directory.
|
||||
*
|
||||
* @returns String The absolute pathname string
|
||||
* @type String
|
||||
*/
|
||||
this.getAbsolutePath = function() {
|
||||
var absolutPath = file.getAbsolutePath();
|
||||
return (absolutPath == null ? "" : absolutPath);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the length of the file represented by this File object.
|
||||
* <br /><br />
|
||||
* The return value is unspecified if this pathname denotes a directory.
|
||||
*
|
||||
* @returns Number The length, in bytes, of the file, or 0L if the file does not exist
|
||||
* @type Number
|
||||
*/
|
||||
this.getLength = function() {
|
||||
return file.length();
|
||||
};
|
||||
|
||||
/**
|
||||
* Tests whether the file represented by this File object is a directory.
|
||||
*
|
||||
* @returns Boolean true if this File object is a directory and exists; false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
this.isDirectory = function() {
|
||||
return file.isDirectory();
|
||||
};
|
||||
|
||||
/**
|
||||
* Tests whether the file represented by this File object is a normal file.
|
||||
* <br /><br />
|
||||
* A file is normal if it is not a directory and, in addition, satisfies
|
||||
* other system-dependent criteria. Any non-directory file created by a
|
||||
* Java application is guaranteed to be a normal file.
|
||||
*
|
||||
* @returns Boolean true if this File object is a normal file and exists; false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
this.isFile = function() {
|
||||
return file.isFile();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the time when the file represented by this File object was last modified.
|
||||
* <br /><br />
|
||||
* A number representing the time the file was last modified,
|
||||
* measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970),
|
||||
* or 0L if the file does not exist or if an I/O error occurs.
|
||||
*
|
||||
* @returns Number in milliseconds since 00:00:00 GMT, January 1, 1970
|
||||
* @type Number
|
||||
*/
|
||||
this.lastModified = function() {
|
||||
return file.lastModified();
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates the directory represented by this File object.
|
||||
*
|
||||
* @returns Boolean true if the directory was created; false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
this.makeDirectory = function() {
|
||||
if (self.isOpened())
|
||||
return false;
|
||||
// don't do anything if file exists or use multi directory version
|
||||
return (file.exists() || file.mkdirs());
|
||||
};
|
||||
|
||||
/**
|
||||
* Renames the file represented by this File object.
|
||||
* <br /><br />
|
||||
* Whether or not this method can move a file from one
|
||||
* filesystem to another is platform-dependent. The return
|
||||
* value should always be checked to make sure that the
|
||||
* rename operation was successful.
|
||||
*
|
||||
* @param {FileObject} toFile as FileObject of the new path
|
||||
* @returns true if the renaming succeeded; false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
this.renameTo = function(toFile) {
|
||||
if (toFile == null) {
|
||||
setError(new IllegalArgumentException("Uninitialized target File object"));
|
||||
return false;
|
||||
}
|
||||
if (self.isOpened()) {
|
||||
setError(new IllegalStateException("An openened file cannot be renamed"));
|
||||
return false;
|
||||
}
|
||||
if (toFile.isOpened()) {
|
||||
setError(new IllegalStateException("You cannot rename to an openened file"));
|
||||
return false;
|
||||
}
|
||||
return file.renameTo(new java.io.File(toFile.getAbsolutePath()));
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the file represented by this File object
|
||||
* has been read entirely and the end of file has been reached.
|
||||
*
|
||||
* @returns Boolean
|
||||
* @type Boolean
|
||||
*/
|
||||
this.eof = function() {
|
||||
if (!self.isOpened()) {
|
||||
setError(new IllegalStateException("File not opened"));
|
||||
return true;
|
||||
}
|
||||
if (!(readerWriter instanceof BufferedReader)) {
|
||||
setError(new IllegalStateException("File not opened for read"));
|
||||
return true;
|
||||
}
|
||||
if (atEOF)
|
||||
return true;
|
||||
if (lastLine != null)
|
||||
return false;
|
||||
try {
|
||||
lastLine = readerWriter.readLine();
|
||||
if (lastLine == null)
|
||||
atEOF = true;
|
||||
return atEOF;
|
||||
} catch (e) {
|
||||
setError(e);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This methods reads all the lines contained in the
|
||||
* file and returns them.
|
||||
*
|
||||
* @return String of all the lines in the file
|
||||
* @type String
|
||||
*/
|
||||
this.readAll = function() {
|
||||
// Open the file for readAll
|
||||
if (self.isOpened()) {
|
||||
setError(new IllegalStateException("File already open"));
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
if (file.exists()) {
|
||||
readerWriter = new BufferedReader(new FileReader(file));
|
||||
} else {
|
||||
setError(new IllegalStateException("File does not exist"));
|
||||
return null;
|
||||
}
|
||||
if (!file.isFile()) {
|
||||
setError(new IllegalStateException("File is not a regular file"));
|
||||
return null;
|
||||
}
|
||||
|
||||
// read content line by line to setup proper eol
|
||||
var buffer = new java.lang.StringBuffer(file.length() * 1.10);
|
||||
while (true) {
|
||||
var line = readerWriter.readLine();
|
||||
if (line == null)
|
||||
break;
|
||||
if (buffer.length() > 0)
|
||||
buffer.append("\n"); // EcmaScript EOL
|
||||
buffer.append(line);
|
||||
}
|
||||
|
||||
// Close the file
|
||||
readerWriter.close();
|
||||
readerWriter = null;
|
||||
return buffer.toString();
|
||||
} catch (e) {
|
||||
readerWriter = null;
|
||||
setError(e);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This method removes a directory recursively .
|
||||
* <br /><br />
|
||||
* DANGER! DANGER! HIGH VOLTAGE!
|
||||
* The directory is deleted recursively without
|
||||
* any warning or precautious measures.
|
||||
*/
|
||||
this.removeDirectory = function() {
|
||||
if (!file.isDirectory())
|
||||
return false;
|
||||
var arr = file.list();
|
||||
for (var i=0; i<arr.length; i++) {
|
||||
var f = new helma.File(file, arr[i]);
|
||||
if (f.isDirectory())
|
||||
f.removeDirectory();
|
||||
else
|
||||
f.remove();
|
||||
}
|
||||
file["delete"]();
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursivly lists all files below a given directory
|
||||
* you may pass a RegExp Pattern to return just
|
||||
* files matching this pattern.
|
||||
*
|
||||
* @param {RegExp} pattern as RegExp, to test each file name against
|
||||
* @returns Array the list of absolute file paths
|
||||
*/
|
||||
this.listRecursive = function(pattern) {
|
||||
if (!file.isDirectory())
|
||||
return false;
|
||||
if (!pattern || pattern.test(file.getName()))
|
||||
var result = [file.getAbsolutePath()];
|
||||
else
|
||||
var result = [];
|
||||
var arr = file.list();
|
||||
for (var i=0; i<arr.length; i++) {
|
||||
var f = new helma.File(file, arr[i]);
|
||||
if (f.isDirectory())
|
||||
result = result.concat(f.listRecursive(pattern));
|
||||
else if (!pattern || pattern.test(arr[i]))
|
||||
result.push(f.getAbsolutePath());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a copy of a file over partitions.
|
||||
*
|
||||
* @param {String|helma.File} dest as a File object or the String of full path of the new file
|
||||
*/
|
||||
this.hardCopy = function(dest) {
|
||||
var inStream = new java.io.BufferedInputStream(
|
||||
new java.io.FileInputStream(file)
|
||||
);
|
||||
var outStream = new java.io.BufferedOutputStream(
|
||||
new java.io.FileOutputStream(dest)
|
||||
);
|
||||
var buffer = java.lang.reflect.Array.newInstance(
|
||||
java.lang.Byte.TYPE, 4096
|
||||
);
|
||||
var bytesRead = 0;
|
||||
while ((bytesRead = inStream.read(buffer, 0, buffer.length)) != -1) {
|
||||
outStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
outStream.flush();
|
||||
inStream.close();
|
||||
outStream.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a file to a new destination directory.
|
||||
*
|
||||
* @param {String} dest as String, the full path of the new file
|
||||
* @returns Boolean true in case file could be moved, false otherwise
|
||||
*/
|
||||
this.move = function(dest) {
|
||||
// instead of using the standard File method renameTo()
|
||||
// do a hardCopy and then remove the source file. This way
|
||||
// file locking shouldn't be an issue
|
||||
self.hardCopy(dest);
|
||||
// remove the source file
|
||||
file["delete"]();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns file as ByteArray.
|
||||
* <br /><br />
|
||||
* Useful for passing it to a function instead of an request object.
|
||||
*/
|
||||
this.toByteArray = function() {
|
||||
if (!this.exists())
|
||||
return null;
|
||||
var body = new java.io.ByteArrayOutputStream();
|
||||
var stream = new java.io.BufferedInputStream(
|
||||
new java.io.FileInputStream(this.getAbsolutePath())
|
||||
);
|
||||
var buf = java.lang.reflect.Array.newInstance(
|
||||
java.lang.Byte.TYPE, 1024
|
||||
);
|
||||
var read;
|
||||
while ((read = stream.read(buf)) > -1)
|
||||
body.write(buf, 0, read);
|
||||
stream.close();
|
||||
return body.toByteArray();
|
||||
};
|
||||
|
||||
for (var i in this)
|
||||
this.dontEnum(i);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/** @ignore */
|
||||
helma.File.toString = function() {
|
||||
return "[helma.File]";
|
||||
};
|
||||
|
||||
|
||||
helma.File.separator = java.io.File.separator;
|
||||
|
||||
|
||||
helma.lib = "File";
|
||||
helma.dontEnum(helma.lib);
|
||||
for (var i in helma[helma.lib])
|
||||
helma[helma.lib].dontEnum(i);
|
||||
for (var i in helma[helma.lib].prototype)
|
||||
helma[helma.lib].prototype.dontEnum(i);
|
||||
delete helma.lib;
|
568
modules/helma/Ftp.js
Normal file
568
modules/helma/Ftp.js
Normal file
|
@ -0,0 +1,568 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2007 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Ftp.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Default properties and methods of the FTP prototype.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/helma/Ftp.js')
|
||||
*/
|
||||
|
||||
// requires helma.File
|
||||
app.addRepository("modules/helma/File.js");
|
||||
|
||||
/**
|
||||
* Define the global namespace if not existing
|
||||
*/
|
||||
if (!global.helma) {
|
||||
global.helma = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for FTP client objects, to send and receive files from an FTP server.
|
||||
* <br /><br />
|
||||
* @class This class represents a FTP client, providing
|
||||
* access to an FTP server.
|
||||
*
|
||||
* @example var ftp = new helma.Ftp("ftp.mydomain.com");
|
||||
* @param {String} server as String, the address of the FTP Server to connect to
|
||||
* @constructor
|
||||
*/
|
||||
helma.Ftp = function(server) {
|
||||
var OK = 0;
|
||||
var SOCKET = 1;
|
||||
var TIMEOUT = 2;
|
||||
var LOGIN = 10;
|
||||
var LOGOUT = 11;
|
||||
var BINARY = 20;
|
||||
var ASCII = 21;
|
||||
var ACTIVE = 22;
|
||||
var PASSIVE = 23;
|
||||
var CD = 30;
|
||||
var LCD = 31;
|
||||
var PWD = 32;
|
||||
var DIR = 33;
|
||||
var MKDIR = 34;
|
||||
var RMDIR = 35;
|
||||
var GET = 40;
|
||||
var PUT = 41;
|
||||
var DELETE = 42;
|
||||
var RENAME = 43;
|
||||
|
||||
var FTP = Packages.org.apache.commons.net.ftp.FTP;
|
||||
var FtpClient = Packages.org.apache.commons.net.ftp.FTPClient;
|
||||
var BufferedInputStream = java.io.BufferedInputStream;
|
||||
var BufferedOutputStream = java.io.BufferedOutputStream;
|
||||
var FileInputStream = java.io.FileInputStream;
|
||||
var FileOutputStream = java.io.FileOutputStream;
|
||||
var ByteArrayInputStream = java.io.ByteArrayInputStream;
|
||||
var ByteArrayOutputStream = java.io.ByteArrayOutputStream;
|
||||
|
||||
var self = this;
|
||||
var className = "helma.Ftp";
|
||||
|
||||
var ftpclient = new FtpClient();
|
||||
var localDir;
|
||||
|
||||
var error = function(methName, errMsg) {
|
||||
var tx = java.lang.Thread.currentThread();
|
||||
tx.dumpStack();
|
||||
app.log("Error in " + className + ":" + methName + ": " + errMsg);
|
||||
return;
|
||||
};
|
||||
|
||||
var debug = function(methName, msg) {
|
||||
msg = msg ? " " + msg : "";
|
||||
app.debug(className + ":" + methName + msg);
|
||||
return;
|
||||
};
|
||||
|
||||
var setStatus = function(status) {
|
||||
if (self.status === OK) {
|
||||
self.status = status;
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
var getStatus = function() {
|
||||
return self.status;
|
||||
};
|
||||
|
||||
this.server = server;
|
||||
this.status = OK;
|
||||
|
||||
/** @ignore */
|
||||
this.toString = function() {
|
||||
return "[helma.Ftp " + server + "]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the default timeout in milliseconds to use when opening a socket.
|
||||
*/
|
||||
this.setReadTimeout = function(timeout) {
|
||||
try {
|
||||
ftpclient.setDefaultTimeout(timeout);
|
||||
debug("setReadTimeout", timeout);
|
||||
return true;
|
||||
} catch(x) {
|
||||
error("setReadTimeout", x);
|
||||
setStatus(SOCKET);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the timeout in milliseconds to use when reading from the data connection.
|
||||
*/
|
||||
this.setTimeout = function(timeout) {
|
||||
try {
|
||||
ftpclient.setDataTimeout(timeout);
|
||||
debug("setTimeout", timeout);
|
||||
return true;
|
||||
} catch(x) {
|
||||
error("setTimeout", x);
|
||||
setStatus(TIMEOUT);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Logs in to the FTP server.
|
||||
*
|
||||
* @param {String} username as String
|
||||
* @param {String} password as String
|
||||
* @return Boolean true if the login was successful, otherwise false
|
||||
* @type Boolean
|
||||
*/
|
||||
this.login = function(username, password) {
|
||||
try {
|
||||
ftpclient.connect(this.server);
|
||||
var result = ftpclient.login(username, password);
|
||||
debug("login", username + "@" + server);
|
||||
return result;
|
||||
} catch(x) {
|
||||
error("login", x);
|
||||
setStatus(LOGIN);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets transfer mode to binary for transmitting images and other non-text files.
|
||||
*
|
||||
* @example ftp.binary();
|
||||
*/
|
||||
this.binary = function() {
|
||||
try {
|
||||
var result = ftpclient.setFileType(FTP.BINARY_FILE_TYPE);
|
||||
debug("binary");
|
||||
return result;
|
||||
} catch(x) {
|
||||
error("binary", x);
|
||||
setStatus(BINARY);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets transfer mode to ascii for transmitting text-based data.
|
||||
*
|
||||
* @example ftp.ascii();
|
||||
*/
|
||||
this.ascii = function() {
|
||||
try {
|
||||
var result = ftpclient.setFileType(FTP.ASCII_FILE_TYPE);
|
||||
debug("ascii");
|
||||
return result;
|
||||
} catch(x) {
|
||||
error("ascii", x);
|
||||
setStatus(ASCII);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Switches the connection to use active mode.
|
||||
*
|
||||
* @example ftp.active();
|
||||
*/
|
||||
this.active = function() {
|
||||
try {
|
||||
ftpclient.enterLocalActiveMode();
|
||||
debug("active");
|
||||
return true;
|
||||
} catch(x) {
|
||||
error("active", x);
|
||||
setStatus(ACTIVE);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Switches the connection to use passive mode.
|
||||
*
|
||||
* @example ftp.passive();
|
||||
*/
|
||||
this.passive = function() {
|
||||
try {
|
||||
ftpclient.enterLocalPassiveMode();
|
||||
debug("passive");
|
||||
return true;
|
||||
} catch(x) {
|
||||
error("passive", x);
|
||||
setStatus(PASSIVE);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the path of the current working directory.
|
||||
*
|
||||
* @example var remotepath = ftp.pwd();
|
||||
* @type String
|
||||
* @return String containing the current working directory path
|
||||
*/
|
||||
this.pwd = function() {
|
||||
try {
|
||||
debug("pwd");
|
||||
return ftpclient.printWorkingDirectory();
|
||||
} catch(x) {
|
||||
error("pwd", x);
|
||||
setStatus(PWD);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a listing of the files contained in a directory on the FTP server.
|
||||
* <br /><br />
|
||||
* Lists the files contained in the current working
|
||||
* directory or, if an alternative path is specified, the
|
||||
* files contained in the specified directory.
|
||||
*
|
||||
* @example var filelist = ftp.dir();
|
||||
* @param {String} path as String, optional alternative directory
|
||||
* @return Array containing the list of files in that directory
|
||||
* @type Array
|
||||
*/
|
||||
this.dir = function(path) {
|
||||
try {
|
||||
debug("dir", path);
|
||||
return ftpclient.listNames(path ? path : ".");
|
||||
} catch(x) {
|
||||
error("dir", x);
|
||||
setStatus(DIR);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new directory on the server.
|
||||
* <br /><br />
|
||||
* The name of the directory is determined as the function's
|
||||
* string parameter. Returns false when an error occured
|
||||
* (e.g. due to access restrictions, directory already
|
||||
* exists etc.), otherwise true.
|
||||
*
|
||||
* @param {String} dir as String, the name of the directory to be created
|
||||
* @return Boolean true if the directory was successfully created, false if there was an error
|
||||
* @type Boolean
|
||||
*/
|
||||
this.mkdir = function(dir) {
|
||||
try {
|
||||
var result = ftpclient.makeDirectory(dir);
|
||||
debug("mkdir", dir);
|
||||
return result;
|
||||
} catch(x) {
|
||||
error("mkdir", x);
|
||||
setStatus(MKDIR);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes a directory on the FTP server.
|
||||
*
|
||||
* @param {String} dir as String, the name of the directory to be deleted
|
||||
* @return Boolean true if the deletion was successful, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
this.rmdir = function(dir) {
|
||||
try {
|
||||
var result = ftpclient.removeDirectory(dir);
|
||||
debug("rmdir", dir);
|
||||
return result;
|
||||
} catch(x) {
|
||||
error("rmdir", x);
|
||||
setStatus(RMDIR);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Changes the working directory on the FTP server.
|
||||
*
|
||||
* @example ftp.cd("/home/users/fred/www"); // use absolute pathname
|
||||
* @example ftp.cd(".."); // change to parent directory
|
||||
* @example ftp.cd("images"); // use relative pathname
|
||||
* @param {String} dir as String, the path that the remote working directory should be changed to
|
||||
*/
|
||||
this.cd = function(path) {
|
||||
try {
|
||||
var result = ftpclient.changeWorkingDirectory(path);
|
||||
debug("cd", path);
|
||||
return result;
|
||||
} catch(x) {
|
||||
error("cd", x);
|
||||
setStatus(CD);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Changes the working directory of the local machine when being connected to an FTP server.
|
||||
*
|
||||
* @example ftp.lcd("/home/users/fred/www"); // use absolute pathname
|
||||
* @example ftp.lcd(".."); // change to parent directory
|
||||
* @example ftp.lcd("images"); // use relative pathname
|
||||
* @param {String} dir as String, the path that the local working directory should be changed to
|
||||
*/
|
||||
this.lcd = function(dir) {
|
||||
try {
|
||||
localDir = new helma.File(dir);
|
||||
if (!localDir.exists()) {
|
||||
localDir.mkdir();
|
||||
debug("lcd", dir);
|
||||
}
|
||||
return true;
|
||||
} catch(x) {
|
||||
error("lcd", x);
|
||||
setStatus(LCD);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transfers a file from the local file system to the remote server.
|
||||
* <br /><br />
|
||||
* Returns true if the transmission was successful, otherwise false.
|
||||
*
|
||||
* @param {String} localFile as String, the name of the file to be uploaded
|
||||
* @param {String} remoteFile as String, the name of the remote destination file
|
||||
* @return Boolean true if the file was successfully uploaded, false if there was an error
|
||||
* @type Boolean
|
||||
*/
|
||||
this.putFile = function(localFile, remoteFile) {
|
||||
try {
|
||||
if (localFile instanceof File || localFile instanceof helma.File) {
|
||||
var f = localFile;
|
||||
} else if (typeof localFile == "string") {
|
||||
if (localDir == null)
|
||||
var f = new helma.File(localFile);
|
||||
else
|
||||
var f = new helma.File(localDir, localFile);
|
||||
}
|
||||
var stream = new BufferedInputStream(
|
||||
new FileInputStream(f.getPath())
|
||||
);
|
||||
if (!remoteFile) {
|
||||
remoteFile = f.getName();
|
||||
}
|
||||
var result = ftpclient.storeFile(remoteFile, stream);
|
||||
stream.close();
|
||||
debug("putFile", remoteFile);
|
||||
return result;
|
||||
} catch(x) {
|
||||
error("putFile", x);
|
||||
setStatus(PUT);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transfers text from a string to a file on the FTP server.
|
||||
*
|
||||
* @example ftp.putString("Hello, World!", "message.txt");
|
||||
* @param {String} str as String, the text content that should be uploaded
|
||||
* @param {String} remoteFile as String, the name of the remote destination file
|
||||
* @param {String} charset as String, optional
|
||||
* @return Boolean true if the file was successfully uploaded, false if there was an error
|
||||
* @type Boolean
|
||||
*/
|
||||
this.putString = function(str, remoteFile, charset) {
|
||||
try {
|
||||
str = new java.lang.String(str);
|
||||
var bytes = charset ? str.getBytes(charset) : str.getBytes();
|
||||
var stream = ByteArrayInputStream(bytes);
|
||||
var result = ftpclient.storeFile(remoteFile, stream);
|
||||
debug("putString", remoteFile);
|
||||
return result;
|
||||
} catch(x) {
|
||||
error("putString", x);
|
||||
setStatus(PUT);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transfers a byte array to a file on the FTP server.
|
||||
* @param {Array} bytes The byte array that should be uploaded
|
||||
* @param {String} remoteFile The name of the remote destination file
|
||||
* @return Boolean True if the file was successfully uploaded, false if there was an error
|
||||
* @type Boolean
|
||||
*/
|
||||
this.putBytes = function(bytes, remoteFile) {
|
||||
try {
|
||||
var stream = ByteArrayInputStream(bytes);
|
||||
var result = ftpclient.storeFile(remoteFile, stream);
|
||||
debug("putBytes", remoteFile);
|
||||
return result;
|
||||
} catch(x) {
|
||||
error("putBytes", x);
|
||||
setStatus(PUT);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transfers a file from the FTP server to the local file system.
|
||||
*
|
||||
* @example ftp.getFile(".htaccess", "htaccess.txt");
|
||||
* @param {String} remoteFile as String, the name of the file that should be downloaded
|
||||
* @param {String} localFile as String, the name which the file should be stored under
|
||||
* @see #cd
|
||||
* @see #lcd
|
||||
*/
|
||||
this.getFile = function(remoteFile, localFile) {
|
||||
try {
|
||||
if (localDir == null)
|
||||
var f = new helma.File(localFile);
|
||||
else
|
||||
var f = new helma.File(localDir, localFile);
|
||||
var stream = new BufferedOutputStream(
|
||||
new FileOutputStream(f.getPath())
|
||||
);
|
||||
var result = ftpclient.retrieveFile(remoteFile, stream);
|
||||
stream.close();
|
||||
debug("getFile", remoteFile);
|
||||
return result;
|
||||
} catch(x) {
|
||||
error("getFile", x);
|
||||
setStatus(GET);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves a file from the FTP server and returns it as string.
|
||||
*
|
||||
* @example var str = ftp.getString("messages.txt");
|
||||
* @param {String} remoteFile as String, the name of the file that should be downloaded
|
||||
* @return String containing the data of the downloaded file
|
||||
* @type String
|
||||
* @see #cd
|
||||
*/
|
||||
this.getString = function(remoteFile) {
|
||||
try {
|
||||
var stream = ByteArrayOutputStream();
|
||||
ftpclient.retrieveFile(remoteFile, stream);
|
||||
debug("getString", remoteFile);
|
||||
return stream.toString();
|
||||
} catch(x) {
|
||||
error("getString", x);
|
||||
setStatus(GET);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes a file on the FTP server.
|
||||
*
|
||||
* @example var str = ftp.deleteFile("messages.txt");
|
||||
* @param {String} remoteFile as String, the name of the file to be deleted
|
||||
* @return Boolean true if the deletion was successful, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
this.deleteFile = function(remoteFile) {
|
||||
try {
|
||||
var result = ftpclient.deleteFile(remoteFile);
|
||||
debug("deleteFile", remoteFile);
|
||||
return result;
|
||||
} catch(x) {
|
||||
error("deleteFile", x);
|
||||
setStatus(DELETE);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Renames a file on the FTP server.
|
||||
*
|
||||
* @example var success = ftp.renameFile("messages.tmp", "messages.txt");
|
||||
* @param {String} from the name of the original file
|
||||
* @param {String} to the new name the original file should get
|
||||
* @return Boolean true if renaming the remote file was successful, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
this.renameFile = function(from, to) {
|
||||
try {
|
||||
var result = ftpclient.rename(from, to);
|
||||
debug("renameFile", from + "->" + to);
|
||||
return result;
|
||||
} catch(x) {
|
||||
error("renameFile", x);
|
||||
setStatus(RENAME);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Terminates the current FTP session.
|
||||
*/
|
||||
this.logout = function() {
|
||||
try {
|
||||
var result = ftpclient.logout();
|
||||
ftpclient.disconnect();
|
||||
debug("logout");
|
||||
return result;
|
||||
} catch(x) {
|
||||
error("logout", x);
|
||||
setStatus(LOGOUT);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for (var i in this)
|
||||
this.dontEnum(i);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/** @ignore */
|
||||
helma.Ftp.toString = function() {
|
||||
return "[helma.Ftp]";
|
||||
};
|
||||
|
||||
|
||||
helma.lib = "Ftp";
|
||||
helma.dontEnum(helma.lib);
|
||||
for (var i in helma[helma.lib])
|
||||
helma[helma.lib].dontEnum(i);
|
||||
for (var i in helma[helma.lib].prototype)
|
||||
helma[helma.lib].prototype.dontEnum(i);
|
||||
delete helma.lib;
|
875
modules/helma/Group.js
Normal file
875
modules/helma/Group.js
Normal file
|
@ -0,0 +1,875 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Group.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview A JavaScript library wrapping
|
||||
* Packages.helma.extensions.helmagroups
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/helma/Group.js')
|
||||
*/
|
||||
|
||||
// Define the global namespace if not existing
|
||||
if (!global.helma) {
|
||||
global.helma = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new helma.Group Object.
|
||||
* @class This is what is retrieved through groups.get(groupName),
|
||||
* wrapping the root object of each group tree.
|
||||
* @param {FIXME} javaGroup FIXME
|
||||
* @constructor
|
||||
*/
|
||||
helma.Group = function(javaGroup) {
|
||||
// private variable containing the wrapper object
|
||||
var groupRoot = new helma.Group.GroupObject(javaGroup.getRoot());
|
||||
|
||||
/**
|
||||
* @returns the wrapped java object Group
|
||||
*/
|
||||
this.getJavaObject = function() {
|
||||
return javaGroup;
|
||||
};
|
||||
|
||||
/**
|
||||
* sets a key/value pair on the group's root,
|
||||
* wraps the function of the wrapper object
|
||||
*/
|
||||
this.set = function(key, val, sendMode) {
|
||||
groupRoot.set(key, val, sendMode);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* removes a key from the group's root,
|
||||
* wraps the function of the root GroupObject
|
||||
*/
|
||||
this.remove = function(key, sendMode) {
|
||||
return groupRoot.remove(key, sendMode);
|
||||
};
|
||||
|
||||
/**
|
||||
* retrieves a key from the group's root,
|
||||
* wraps the function of the root GroupObject
|
||||
*/
|
||||
this.get = function(key) {
|
||||
return groupRoot.get(key);
|
||||
};
|
||||
|
||||
/**
|
||||
* @see helma.Group.GroupObject.listChildren
|
||||
*/
|
||||
this.listChildren = function() {
|
||||
return groupRoot.listChildren();
|
||||
};
|
||||
|
||||
/**
|
||||
* @see helma.Group.GroupObject.listProperties
|
||||
*/
|
||||
this.listProperties = function() {
|
||||
return groupRoot.listProperties();
|
||||
};
|
||||
|
||||
/**
|
||||
* @see helma.Group.GroupObject.countChildren
|
||||
*/
|
||||
this.countChildren = function() {
|
||||
return groupRoot.countChildren();
|
||||
};
|
||||
|
||||
/**
|
||||
* @see helma.Group.GroupObject.countProperties
|
||||
*/
|
||||
this.countProperties = function() {
|
||||
return groupRoot.countProperties();
|
||||
};
|
||||
|
||||
/**
|
||||
* calls a function in all connected applications
|
||||
* (to be specific: in all registered localClients).
|
||||
* @param method name of the method in xmlrpc-style: test
|
||||
* is called as root.test(), stories.137.render
|
||||
* is called as root.stories.get("137").render() etc etc.
|
||||
* @param argArr array of arguments to the remote method
|
||||
* @param sendMode as defined for helma.Group.GroupObject
|
||||
* @returns array of result objects
|
||||
*/
|
||||
this.callFunction = function(method, argArr, sendMode) {
|
||||
groups.checkWriteAccess(javaGroup);
|
||||
if (sendMode == null) {
|
||||
sendMode = helma.Group.GroupObject.DEFAULT_GET;
|
||||
}
|
||||
var argVec = new java.util.Vector();
|
||||
for (var i=0; i<argArr.length; i++) {
|
||||
argVec.add(argArr[i]);
|
||||
}
|
||||
var resVec = javaGroup.execute(method, argVec, sendMode,
|
||||
javaGroup.DEFAULT_EXECUTE_TIMEOUT);
|
||||
var resArr = [];
|
||||
for (var i=0; i<resVec.size(); i++) {
|
||||
resArr[i] = resVec.get(i);
|
||||
}
|
||||
return resArr;
|
||||
};
|
||||
|
||||
this.toString = function() {
|
||||
return javaGroup.toString();
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a new helma.Group.GroupObject.
|
||||
* @class This class wraps the java GroupObject
|
||||
* and provides several methods for retrieving and manipulating properties.
|
||||
* @param {Object} Instance of helma.extensions.helmagroups.GroupObject
|
||||
* @constructor
|
||||
*/
|
||||
helma.Group.GroupObject = function(javaGroupObject) {
|
||||
var helmagroups = Packages.helma.extensions.helmagroups;
|
||||
|
||||
if (!javaGroupObject) {
|
||||
var javaGroupObject = new helmagroups.GroupObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* private method that returns true if the group
|
||||
* is writable
|
||||
* @returns Boolean
|
||||
*/
|
||||
var checkWriteAccess = function() {
|
||||
if (javaGroupObject.getState() == helmagroups.GroupObject.REPLICATED) {
|
||||
groups.checkWriteAccess(javaGroupObject.getGroup());
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the key passed as argument is a path
|
||||
* (either an Array or a String that contains separator characters)
|
||||
* @returns Boolean
|
||||
*/
|
||||
var keyIsPath = function(key) {
|
||||
var separator = helmagroups.GroupObject.SEPARATOR;
|
||||
if ((key instanceof Array) || key.indexOf(separator) != -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the last element if the key passed as argument is a path.
|
||||
* @returns Boolean
|
||||
*/
|
||||
var getLastKeyElement = function(key) {
|
||||
var separator = helmagroups.GroupObject.SEPARATOR;
|
||||
if (!(key instanceof Array) && key.indexOf(separator) != -1) {
|
||||
if (key.charAt(key.length-1)==separator) {
|
||||
key = key.substring(0, key.length-1);
|
||||
}
|
||||
key = key.split(separator);
|
||||
}
|
||||
if (key instanceof Array) {
|
||||
return key[key.length-1];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* if key is a path, walks through the path and returns the lowest GroupObject.
|
||||
* if tree ends somewhere in the path, function returns null.
|
||||
* @returns null or GroupObject
|
||||
*/
|
||||
var walkPath = function(obj, key) {
|
||||
var separator = helmagroups.GroupObject.SEPARATOR;
|
||||
if (!(key instanceof Array) && key.indexOf(separator) != -1) {
|
||||
if (key.charAt(key.length-1)==separator) {
|
||||
key = key.substring(0, key.length-1);
|
||||
}
|
||||
key = key.split(separator);
|
||||
}
|
||||
if (key instanceof Array) {
|
||||
// loop down until end of array
|
||||
for (var i=0; i<key.length-1; i++) {
|
||||
var nextObj = obj.get(key[i]);
|
||||
if (nextObj == null || !(nextObj instanceof helma.Group.GroupObject)) {
|
||||
return null;
|
||||
}
|
||||
obj = nextObj;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* if key is a path, walks through the path and returns the lowest GroupObject.
|
||||
* if tree ends somewhere in the path, function creates the missing GroupObjects.
|
||||
* @returns helma.Group.GroupObject
|
||||
*/
|
||||
var createPath = function(obj, key) {
|
||||
var separator = helmagroups.GroupObject.SEPARATOR;
|
||||
if (!(key instanceof Array) && key.indexOf(separator) != -1) {
|
||||
if (key.charAt(key.length-1)==separator) {
|
||||
key = key.substring(0, key.length-1);
|
||||
}
|
||||
key = key.split(separator);
|
||||
}
|
||||
if (key instanceof Array) {
|
||||
// loop down until end of array
|
||||
for (var i=0; i<key.length-1; i++) {
|
||||
var nextObj = obj.get(key[i]);
|
||||
if (nextObj == null || !(nextObj instanceof helma.Group.GroupObject)) {
|
||||
nextObj = new helma.Group.GroupObject();
|
||||
obj.set(key[i], nextObj);
|
||||
}
|
||||
obj = nextObj;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the wrapped java GroupObject.
|
||||
* @return Instance of helma.extensions.helmagroups.GroupObject;
|
||||
* @type helma.extensions.helmagroups.GroupObject
|
||||
*/
|
||||
this.getJavaObject = function() {
|
||||
return javaGroupObject;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets a property or a child GroupObject in this instance.
|
||||
* The Key may be a String, an Array or a String with separator characters ("/").
|
||||
* In the latter two cases the argument is considered a path and
|
||||
* all GroupObjects along this path are created if necessary.
|
||||
* @param {Object} key Either
|
||||
* <ul>
|
||||
* <li>a String</li>
|
||||
* <li>a String containing slashes</li>
|
||||
* <li>an Array containing String keys</li>
|
||||
* </ul>
|
||||
* @param {Number} The value to set the property to.
|
||||
* @param {Object} The mode to use when committing the change to
|
||||
* the helma.Group
|
||||
*/
|
||||
this.set = function(key, val, sendMode) {
|
||||
if (!key) {
|
||||
throw "helma.Group.GroupObject.set(): key can't be null";
|
||||
}
|
||||
checkWriteAccess();
|
||||
// check content type of value:
|
||||
var ok = false;
|
||||
if (val == null)
|
||||
ok = true;
|
||||
else if (typeof(val) == "string")
|
||||
ok = true;
|
||||
else if (typeof(val) == "number")
|
||||
ok = true;
|
||||
else if (typeof(val) == "boolean")
|
||||
ok = true;
|
||||
else if (val instanceof Date)
|
||||
ok = true;
|
||||
else if (val instanceof helma.Group.GroupObject)
|
||||
ok = true;
|
||||
if (ok == false) {
|
||||
throw "only primitive values, Date and helma.Group.GroupObject allowed in helma.Group.GroupObject.set()";
|
||||
}
|
||||
if (sendMode == null) {
|
||||
sendMode = helma.Group.GroupObject.DEFAULT_GET;
|
||||
}
|
||||
|
||||
if (keyIsPath(key)) {
|
||||
var obj = createPath(this, key);
|
||||
if (obj != null) {
|
||||
obj.set(getLastKeyElement(key), val, sendMode);
|
||||
}
|
||||
} else {
|
||||
// set a property/child of this object
|
||||
if (val == null) {
|
||||
// null values aren't permitted in the group,
|
||||
// setting a property to null is the same as deleting it
|
||||
this.remove(key, sendMode);
|
||||
} else if (val instanceof helma.Group.GroupObject) {
|
||||
// replicate helma.Group.GroupObject
|
||||
javaGroupObject.put(key, val.getJavaObject(), sendMode);
|
||||
} else {
|
||||
// put the primitive property (or maybe replicate,
|
||||
// decision's up to helma.Group.GroupObject)
|
||||
if (val instanceof Date) {
|
||||
// convert javascript dates to java dates
|
||||
val = new java.util.Date(val.getTime());
|
||||
}
|
||||
javaGroupObject.put(key, val, sendMode);
|
||||
}
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Removes a property or a child GroupObject from this instance.
|
||||
* The Key may be a String, an Array or a String with separator characters ("/").
|
||||
* In the latter two cases the argument is considered a path and
|
||||
* the function walks down that path to find the GroupObject and
|
||||
* deletes it.
|
||||
* @param {Object} key Either
|
||||
* <ul>
|
||||
* <li>a String</li>
|
||||
* <li>a String containing slashes</li>
|
||||
* <li>an Array containing String keys</li>
|
||||
* </ul>
|
||||
* @param {Number} The mode to use when committing the change to
|
||||
* the helma.Group
|
||||
*/
|
||||
this.remove = function(key, sendMode) {
|
||||
checkWriteAccess();
|
||||
if (sendMode == null) {
|
||||
sendMode = helma.Group.GroupObject.DEFAULT_GET;
|
||||
}
|
||||
if (keyIsPath(key)) {
|
||||
var obj = walkPath(this, key);
|
||||
if (obj != null) {
|
||||
obj.remove(getLastKeyElement(key));
|
||||
}
|
||||
} else {
|
||||
javaGroupObject.remove(key, sendMode);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns either a property or a child GroupObject from
|
||||
* this GroupObject instance. The key passed as argument
|
||||
* may be a String, an Array containing Strings or a
|
||||
* String containing separator characters ("/"). In the latter
|
||||
* two cases the argument is considered a path and
|
||||
* the function walks down that path to find the requested
|
||||
* GroupObject.
|
||||
* @param {Object} key Either
|
||||
* <ul>
|
||||
* <li>a String</li>
|
||||
* <li>a String containing slashes</li>
|
||||
* <li>an Array containing String keys</li>
|
||||
* </ul>
|
||||
* @return Depending on the argument either the appropriate property
|
||||
* value or a helma.Group.GroupObject
|
||||
* @type Object
|
||||
*/
|
||||
this.get = function(key) {
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
if (keyIsPath(key)) {
|
||||
var obj = walkPath(this, key);
|
||||
if (obj != null) {
|
||||
return obj.get(getLastKeyElement(key));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else if (javaGroupObject.hasProperty(key)) {
|
||||
// we got a primitive property
|
||||
var val = javaGroupObject.getProperty(key);
|
||||
if (val instanceof java.util.Date) {
|
||||
// convert java dates to javascript dates
|
||||
val = new Date(val);
|
||||
}
|
||||
return val;
|
||||
} else if (javaGroupObject.hasChild(key)) {
|
||||
// we got a child object
|
||||
return new helma.Group.GroupObject(javaGroupObject.getChild(key));
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets a property from this GroupObject. The key passed as argument
|
||||
* is always considered a property even if it contains a slash.
|
||||
* This is actually a workaround for the fact that other
|
||||
* instances of the group not using the javascript extension aren't forbidden
|
||||
* to add properties containing a slash in the property's name.
|
||||
* So, using this extension we can at least read the property.
|
||||
* @param {String} key The name of the property to return
|
||||
* @returns The value of the property
|
||||
* @type Object
|
||||
*/
|
||||
this.getProperty = function(key) {
|
||||
if (key == null) {
|
||||
return null;
|
||||
} else if (javaGroupObject.hasProperty(key)) {
|
||||
// we got a primitive property
|
||||
var val = javaGroupObject.getProperty(key);
|
||||
if (val instanceof java.util.Date) {
|
||||
// convert java dates to javascript dates
|
||||
val = new Date(val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Exchanges this GroupObject with the one passed
|
||||
* as argument. This is done by exchanging the wrapped
|
||||
* instance of helma.extensions.helmagroups.GroupObject
|
||||
* @param {GroupObject} The GroupObject to use
|
||||
* @returns The GroupObject with the exchanged wrapped java object
|
||||
* @type GroupObject
|
||||
*/
|
||||
this.wrap = function(newGroupObject) {
|
||||
checkWriteAccess();
|
||||
if (javaGroupObject.getState() != helmagroups.GroupObject.REPLICATED) {
|
||||
throw "helma.Group.GroupObject.wrap() may only be called on replicated GroupObjects";
|
||||
}
|
||||
if (newGroupObject == null || !(newGroupObject instanceof helma.Group.GroupObject)) {
|
||||
throw "helma.Group.GroupObject.wrap() requires a helma.Group.GroupObject as an argument";
|
||||
}
|
||||
javaGroupObject.wrap(newGroupObject.getJavaObject());
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clones this GroupObject and returns it.
|
||||
* This method should be considered if many properties
|
||||
* of a GroupObject must be set or modified since every
|
||||
* change to an already replicated GroupObject will
|
||||
* result in immediate network traffic. Using unwrap
|
||||
* one can modify several properties and then commit
|
||||
* the GroupObject at once using {@link #wrap).
|
||||
* @returns A clone of this GroupObject
|
||||
* @type GroupObject
|
||||
*/
|
||||
this.unwrap = function() {
|
||||
var javaGroupObjectClone = javaGroupObject.clone();
|
||||
javaGroupObjectClone.setChildren(new java.util.Hashtable());
|
||||
javaGroupObjectClone.setState(helmagroups.GroupObject.LOCAL);
|
||||
javaGroupObjectClone.setPath(null);
|
||||
return new helma.Group.GroupObject(javaGroupObjectClone);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts this GroupObject into a vanilla Object
|
||||
* @returns An Object containing all properties of this GroupObject
|
||||
* @type Object
|
||||
*/
|
||||
this.toJSObject = function() {
|
||||
var key;
|
||||
var obj = {};
|
||||
var e = javaGroupObject.properties();
|
||||
while(e.hasMoreElements()) {
|
||||
obj[key = e.nextElement()] = javaGroupObject.getProperty(key);
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an Array containing all child GroupObjects
|
||||
* @returns An Array containing GroupObjects
|
||||
* @type Array
|
||||
*/
|
||||
this.listChildren = function() {
|
||||
var arr = [];
|
||||
var e = javaGroupObject.children();
|
||||
while(e.hasMoreElements()) {
|
||||
arr.push(e.nextElement());
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an Array containing all property
|
||||
* names of this GroupObject instance
|
||||
* @returns An Array containing property names
|
||||
* @type Array
|
||||
*/
|
||||
this.listProperties = function() {
|
||||
var arr = [];
|
||||
var e = javaGroupObject.properties();
|
||||
while(e.hasMoreElements()) {
|
||||
arr.push(e.nextElement());
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the number of child GroupObjects
|
||||
* @returns The number of child GroupObjects of this
|
||||
* helma.Group.GroupObject instance
|
||||
* @type Number
|
||||
*/
|
||||
this.countChildren = function() {
|
||||
var ht = javaGroupObject.getChildren();
|
||||
if (ht == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return ht.size();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the number of properties of this GroupObject
|
||||
* @return The number of properties
|
||||
* @type Number
|
||||
*/
|
||||
this.countProperties = function() {
|
||||
var ht = javaGroupObject.getProperties();
|
||||
return (ht == null) ? 0 : ht.size();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the GroupObject is <em>not</em> replicated
|
||||
* @returns True if this GroupObject is still local
|
||||
* @type Boolean
|
||||
*/
|
||||
this.isLocal = function() {
|
||||
return (javaGroupObject.getState()
|
||||
== helmagroups.GroupObject.LOCAL);
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
this.toString = function() {
|
||||
return javaGroupObject.toString();
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Static properties of GroupObject constructor function.
|
||||
* These values determine if and for how many confirmation of the
|
||||
* group members this instance waits after a modification.
|
||||
* These values are passed through to org.jgroups.blocks.GroupRequest,
|
||||
* for further comments see the sourcecode of that class
|
||||
*/
|
||||
// wait just for the first response
|
||||
helma.Group.GroupObject.GET_FIRST = 1;
|
||||
// wait until all members have responded
|
||||
helma.Group.GroupObject.GET_ALL = 2;
|
||||
// wait for majority (50% + 1) to respond
|
||||
helma.Group.GroupObject.GET_MAJORITY = 3;
|
||||
// wait for majority of all members (may block!)
|
||||
helma.Group.GroupObject.GET_ABS_MAJORITY = 4;
|
||||
// don't wait for any response (fire & forget)
|
||||
helma.Group.GroupObject.GET_NONE = 6;
|
||||
// default: wait for all responses
|
||||
helma.Group.GroupObject.DEFAULT_GET = helma.Group.GroupObject.GET_ALL;
|
||||
|
||||
/**
|
||||
* This is mounted as "groups".
|
||||
* @class The root for all groups started in this application
|
||||
* @constructor
|
||||
*/
|
||||
helma.Group.Manager = function() {
|
||||
var helmagroups = Packages.helma.extensions.helmagroups;
|
||||
var extension = helmagroups.GroupExtension.self;
|
||||
|
||||
if (extension == null) {
|
||||
throw("helma.Group.Manager requires the HelmaGroups Extension \
|
||||
located in lib/ext or the application's top-level directory \
|
||||
[http://adele.helma.org/download/helma/contrib/helmagroups/]");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get a java object Group for a groupname.
|
||||
* object is fetched regardless of connection status
|
||||
* @returns null if group is not defined
|
||||
*/
|
||||
var getJavaGroup = function(name) {
|
||||
return extension.checkAppLink(app.name).get(name);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* visible to scripting env: get a group, wrapped as a javascript helma.Group object.
|
||||
* the group must be defined in app.properties: group.nameXX = <configfile>
|
||||
* and can then be accessed like this group.get("nameXX")
|
||||
* @returns null if group is not defined or not connected
|
||||
*/
|
||||
this.get = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null || javaGroup.isConnected() == false) {
|
||||
return null;
|
||||
} else {
|
||||
return new helma.Group(javaGroup);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* checks for write access to a group according to app.properties
|
||||
* group.nameXX.writable must be true so that this function returns
|
||||
* @param nameOrJGroup can be the name of a group or a java Group itself
|
||||
* @throws an error if group is not writable
|
||||
*/
|
||||
this.checkWriteAccess = function(nameOrJGroup) {
|
||||
var extension = helmagroups.GroupExtension.self;
|
||||
var jAppLink = extension.checkAppLink(app.name);
|
||||
if (nameOrJGroup instanceof helmagroups.Group) {
|
||||
// arg was a Group
|
||||
var javaGroup = nameOrJGroup;
|
||||
} else {
|
||||
// arg was the name of the group
|
||||
var javaGroup = jAppLink.get(nameOrJGroup);
|
||||
}
|
||||
if (javaGroup != null && jAppLink.isWritable(javaGroup) == false) {
|
||||
throw("tried to access write-protected group");
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* try to connect a group
|
||||
* @returns false if group is not found
|
||||
*/
|
||||
this.connect = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null) {
|
||||
return false;
|
||||
}
|
||||
javaGroup.connect();
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* try to disconnect from a group
|
||||
* @returns false if group is not found
|
||||
*/
|
||||
this.disconnect = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null) {
|
||||
return false;
|
||||
}
|
||||
javaGroup.disconnect();
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* try to disconnect and connect again to a group
|
||||
* @returns false if group is not found
|
||||
*/
|
||||
this.reconnect = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null) {
|
||||
return false;
|
||||
}
|
||||
javaGroup.reconnect();
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* try to reset a group (if application may write in group).
|
||||
* all instances of the group empty their cache.
|
||||
* @returns false if group is not found
|
||||
*/
|
||||
this.reset = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null) {
|
||||
return false;
|
||||
}
|
||||
groups.checkWriteAccess(javaGroup);
|
||||
javaGroup.reset();
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* try to destroy a group (if application may write in group).
|
||||
* all other instances of the group disconnect
|
||||
* @returns false if group is not found
|
||||
*/
|
||||
this.destroy = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null) {
|
||||
return false;
|
||||
}
|
||||
groups.checkWriteAccess(javaGroup);
|
||||
javaGroup.destroy();
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* try to restart a group (if application may write in group).
|
||||
* all other instances of the group disconnect and reconnect - each app after a different pause
|
||||
* so that they don't all come up at the same moment
|
||||
* @returns false if group is not found
|
||||
*/
|
||||
this.restart = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null) {
|
||||
return false;
|
||||
}
|
||||
groups.checkWriteAccess(javaGroup);
|
||||
javaGroup.restart();
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* list the members of this group (ie instances of Group, one helma server is one instance)
|
||||
* @returns array of strings, false if group is not found
|
||||
*/
|
||||
this.listMembers = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null) {
|
||||
return false;
|
||||
}
|
||||
var addrArr = javaGroup.info.listMembers();
|
||||
var arr = [];
|
||||
for (var i=0; i<addrArr.length; i++) {
|
||||
arr[arr.length] = helmagroups.Config.addressToString(addrArr[i]);
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* lists the members applications of this group (may be more than one per instance but also none)
|
||||
* @returns array of strings, false if group is not found
|
||||
*/
|
||||
this.listMemberApps = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null) {
|
||||
return false;
|
||||
}
|
||||
var appsArr = javaGroup.info.listMemberApps();
|
||||
var arr = [];
|
||||
for (var i=0; i<appsArr.length; i++) {
|
||||
arr[arr.length] = appsArr[i];
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* dumps the keys of the group to a string
|
||||
* @returns string, notice if group is not found
|
||||
*/
|
||||
this.getContent = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null) {
|
||||
return "[not connected]";
|
||||
}
|
||||
return javaGroup.info.print();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* dumps the keys and the content of the group to a string
|
||||
* @returns string, notice if group is not found
|
||||
*/
|
||||
this.getFullContent = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null) {
|
||||
return "[not connected]";
|
||||
}
|
||||
return javaGroup.info.printFull();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* dumps the config of the jgroups stack to a string
|
||||
* @returns string, false if group is not found
|
||||
*/
|
||||
this.getConfig = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null) {
|
||||
return false;
|
||||
}
|
||||
return javaGroup.info.printStack(false);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* dumps the config of the jgroups stack including all properties to a string
|
||||
* @returns string, false if group is not found
|
||||
*/
|
||||
this.getFullConfig = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null) {
|
||||
return false;
|
||||
}
|
||||
return javaGroup.info.printStack(true);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* returns the connection identifier of the Group instance (localname + multicast-target)
|
||||
* @returns string, false if group is not found
|
||||
*/
|
||||
this.getConnection = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null) {
|
||||
return false;
|
||||
}
|
||||
return javaGroup.info.getConnection();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* returns true/false if the group is connected
|
||||
*/
|
||||
this.isConnected = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null) {
|
||||
return false;
|
||||
}
|
||||
return javaGroup.isConnected();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* returns the total number of groupobjects in this group
|
||||
*/
|
||||
this.size = function(name) {
|
||||
var javaGroup = getJavaGroup(name);
|
||||
if (javaGroup == null) {
|
||||
return false;
|
||||
}
|
||||
return javaGroup.size();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* returns the total number of groupobjects in this group
|
||||
*/
|
||||
this.count = function(name) {
|
||||
return this.size(name);
|
||||
};
|
||||
|
||||
this.toString = function() {
|
||||
return "[helma.Group.Manager]";
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// Instantiate helma.Group.Manager as "groups" variable
|
||||
var groups = new helma.Group.Manager();
|
960
modules/helma/Html.js
Normal file
960
modules/helma/Html.js
Normal file
|
@ -0,0 +1,960 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Html.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the helma.Html
|
||||
* and helma.Html.Tablewriter classes.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/helma/Html.js')
|
||||
*/
|
||||
|
||||
// take care of any dependencies
|
||||
app.addRepository('modules/core/String.js');
|
||||
app.addRepository('modules/core/Object.js');
|
||||
app.addRepository('modules/core/Array.js');
|
||||
|
||||
/**
|
||||
* Define the global namespace if not existing
|
||||
*/
|
||||
if (!global.helma) {
|
||||
global.helma = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of helma.Html
|
||||
* @class This class provides various methods for rendering
|
||||
* X/Html tags.
|
||||
* @returns A newly created instance of helma.Html
|
||||
* @constructor
|
||||
*/
|
||||
helma.Html = function() {
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Static helper method that renders an arbitrary markup part.
|
||||
* @param {String} name The element's name
|
||||
* @param {String} start Prefix of each rendered element
|
||||
* @param {String} end Suffix of each rendered element
|
||||
* @param {Object} attr Optional element attributes
|
||||
*/
|
||||
helma.Html.renderMarkupPart = function(name, start, end, attr) {
|
||||
res.write(start);
|
||||
res.write(name);
|
||||
if (attr) {
|
||||
for (var i in attr) {
|
||||
if (i == "prefix" || i == "suffix" ||
|
||||
i == "default" || attr[i] == null) {
|
||||
continue;
|
||||
}
|
||||
res.write(" ");
|
||||
res.write(i);
|
||||
res.write("=\"");
|
||||
res.write(attr[i]);
|
||||
res.write("\"");
|
||||
}
|
||||
}
|
||||
res.write(end);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Static helper method used in helma.Html.checkBox
|
||||
* and helma.Html.dropDown to check if a current value
|
||||
* matches against one or more selected values passed
|
||||
* as argument
|
||||
* @param {String} value The current value to check
|
||||
* @param {String|Array} selectedValue Either a single
|
||||
* value to check against the current value, or an array
|
||||
* containing values.
|
||||
* @returns True in case the value is among the selected
|
||||
* values, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
helma.Html.isSelected = function(value, selectedValue) {
|
||||
if (selectedValue == null || value == null)
|
||||
return false;
|
||||
if (selectedValue instanceof Array)
|
||||
return selectedValue.contains(value);
|
||||
return value == selectedValue;
|
||||
};
|
||||
|
||||
|
||||
/** @ignore */
|
||||
helma.Html.prototype.toString = function() {
|
||||
return "[helma.Html]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the opening tag of an arbitrary x/html tag
|
||||
* @param {String} name The tag name
|
||||
* @param {Object} attr An optional object containing element attributes
|
||||
*/
|
||||
helma.Html.prototype.openTag = function(name, attr) {
|
||||
helma.Html.renderMarkupPart(name, "<", ">", attr);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the opening tag of an arbitrary x/html tag
|
||||
* @param {String} name The tag name
|
||||
* @param {Object} attr An optional object containing element attributes
|
||||
* @returns The rendered x/html opening tag
|
||||
* @type String
|
||||
* @see #openTag
|
||||
*/
|
||||
helma.Html.prototype.openTagAsString = function(name, attr) {
|
||||
res.push();
|
||||
helma.Html.renderMarkupPart(name, "<", ">", attr);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the closing tag of an arbitrary x/html tag
|
||||
* @param {String} name The tag name
|
||||
*/
|
||||
helma.Html.prototype.closeTag = function(name) {
|
||||
helma.Html.renderMarkupPart(name, "</", ">", null);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the closing tag of an arbitray x/html element
|
||||
* @param {String} name The tag name
|
||||
* @returns The rendered closing tag
|
||||
* @type String
|
||||
* @see #closeTag
|
||||
*/
|
||||
helma.Html.prototype.closeTagAsString = function(name) {
|
||||
res.push();
|
||||
helma.Html.renderMarkupPart(name, "</", ">", null);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders an empty arbitrary x/html tag ("contentless tag")
|
||||
* @param {String} name The tag name
|
||||
* @param {Object} attr An optional object containing tag attributes
|
||||
*/
|
||||
helma.Html.prototype.tag = function(name, attr) {
|
||||
helma.Html.renderMarkupPart(name, "<", " />", attr);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an empty arbitrary x/html tag ("contentless tag")
|
||||
* @param {String} name The tag name
|
||||
* @param {Object} attr An optional object containing tag attributes
|
||||
* @returns The rendered element
|
||||
* @type String
|
||||
* @see #tag
|
||||
*/
|
||||
helma.Html.prototype.tagAsString = function(name, attr) {
|
||||
res.push();
|
||||
helma.Html.renderMarkupPart(name, "<", " />", attr);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders an arbitrary x/html element
|
||||
* @param {String} name The element name
|
||||
* @param {String} str The content of the element
|
||||
* @param {Object} attr An optional object containing element attributes
|
||||
*/
|
||||
helma.Html.prototype.element = function(name, str, attr) {
|
||||
helma.Html.renderMarkupPart(name, "<", ">", attr);
|
||||
res.write(str);
|
||||
helma.Html.renderMarkupPart(name, "</", ">");
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return an arbitrary x/html element
|
||||
* @param {String} name The element name
|
||||
* @param {String} str The content of the element
|
||||
* @param {Object} attr An optional object containing element attributes
|
||||
* @returns The rendered element
|
||||
* @type String
|
||||
* @see #element
|
||||
*/
|
||||
helma.Html.prototype.elementAsString = function(name, str, attr) {
|
||||
res.push();
|
||||
this.element(name, str, attr);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders an x/html link tag
|
||||
* @param {Object} attr An object containing the link attributes
|
||||
* @param {String} text The text to appear as link
|
||||
*/
|
||||
helma.Html.prototype.link = function(attr, text) {
|
||||
if (!attr) {
|
||||
res.write("[Html.link: insufficient arguments]");
|
||||
return;
|
||||
}
|
||||
this.openTag("a", attr);
|
||||
res.write(text);
|
||||
this.closeTag("a");
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a rendered x/html link tag
|
||||
* @param {Object} attr An object containing the link attributes
|
||||
* @param {String} text The text to appear as link
|
||||
* @returns The rendered link tag
|
||||
* @type String
|
||||
* @see #link
|
||||
*/
|
||||
helma.Html.prototype.linkAsString = function(attr, text) {
|
||||
res.push();
|
||||
this.link(attr, text);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders an x/html input tag of type "hidden"
|
||||
* @param {Object} param An object containing the tag attributes
|
||||
*/
|
||||
helma.Html.prototype.hidden = function(param) {
|
||||
if (!param) {
|
||||
res.write("[Html.hidden: insufficient arguments]");
|
||||
return;
|
||||
}
|
||||
var attr = Object.prototype.reduce.call(param);
|
||||
attr.type = "hidden";
|
||||
attr.value = (attr.value != null) ? encodeForm(attr.value) : "";
|
||||
this.tag("input", attr);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a rendered x/html input tag of type "hidden"
|
||||
* @param {Object} attr An object containing the tag attributes
|
||||
* @returns The rendered input element
|
||||
* @type String
|
||||
* @see #hidden
|
||||
*/
|
||||
helma.Html.prototype.hiddenAsString = function(attr) {
|
||||
res.push();
|
||||
this.hidden(attr);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders an x/html text input tag
|
||||
* @param {Object} param An object containing the tag attributes
|
||||
*/
|
||||
helma.Html.prototype.input = function(param) {
|
||||
if (!param) {
|
||||
res.write("[Html.input: insufficient arguments]");
|
||||
return;
|
||||
}
|
||||
var attr = Object.prototype.reduce.call(param);
|
||||
attr.type = "text";
|
||||
if (!attr.size)
|
||||
attr.size = 20;
|
||||
attr.value = (attr.value != null) ? encodeForm(attr.value) : "";
|
||||
this.tag("input", attr);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a rendered x/html text input tag
|
||||
* @param {Object} attr An object containing the tag attributes
|
||||
* @returns The rendered text input tag
|
||||
* @type String
|
||||
* @see #input
|
||||
*/
|
||||
helma.Html.prototype.inputAsString = function(attr) {
|
||||
res.push();
|
||||
this.input(attr);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders an x/html textarea tag
|
||||
* @param {Object} param An object containing the tag attributes
|
||||
*/
|
||||
helma.Html.prototype.textArea = function(param) {
|
||||
if (!param) {
|
||||
res.write("[Html.textArea: insufficient arguments]");
|
||||
return;
|
||||
}
|
||||
var attr = Object.prototype.reduce.call(param);
|
||||
var value = (attr.value != null) ? encodeForm(attr.value) : "";
|
||||
delete attr.value;
|
||||
this.openTag("textarea", attr);
|
||||
res.write(value);
|
||||
this.closeTag("textarea");
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a rendered x/html textarea tag
|
||||
* @param {Object} attr An object containing the tag attributes
|
||||
* @returns The rendered textarea tag
|
||||
* @type String
|
||||
* @see #textArea
|
||||
*/
|
||||
helma.Html.prototype.textAreaAsString = function(attr) {
|
||||
res.push();
|
||||
this.textArea(attr);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders an x/html checkbox input tag
|
||||
* @param {Object} param An object containing the tag attributes
|
||||
*/
|
||||
helma.Html.prototype.checkBox = function(param) {
|
||||
if (!param) {
|
||||
res.write("[Html.checkBox: insufficient arguments]");
|
||||
return;
|
||||
}
|
||||
var attr = Object.prototype.reduce.call(param);
|
||||
attr.type = "checkbox";
|
||||
if (attr.selectedValue != null) {
|
||||
if (helma.Html.isSelected(param.value, param.selectedValue))
|
||||
attr.checked = "checked";
|
||||
else
|
||||
delete attr.checked;
|
||||
delete attr.selectedValue;
|
||||
}
|
||||
this.tag("input", attr);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a rendered x/html checkbox input tag
|
||||
* @param {Object} attr An object containing the tag attributes
|
||||
* @returns The rendered checkbox tag
|
||||
* @type String
|
||||
* @see #checkBox
|
||||
*/
|
||||
helma.Html.prototype.checkBoxAsString = function(attr) {
|
||||
res.push();
|
||||
this.checkBox(attr);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders an x/html radiobutton input tag
|
||||
* @param {Object} param An object containing the tag attributes
|
||||
*/
|
||||
helma.Html.prototype.radioButton = function(param) {
|
||||
if (!param) {
|
||||
res.write("[Html.radioButton: insufficient arguments]");
|
||||
return;
|
||||
}
|
||||
var attr = Object.prototype.reduce.call(param);
|
||||
attr.type = "radio";
|
||||
if (attr.selectedValue != null) {
|
||||
if (attr.value == attr.selectedValue)
|
||||
attr.checked = "checked";
|
||||
else
|
||||
delete attr.checked;
|
||||
delete attr.selectedValue;
|
||||
}
|
||||
this.tag("input", attr);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a rendered x/html radio input tag
|
||||
* @param {Object} attr An object containing the tag attributes
|
||||
* @returns The rendered element
|
||||
* @type String
|
||||
* @see #radioButton
|
||||
*/
|
||||
helma.Html.prototype.radioButtonAsString = function(attr) {
|
||||
res.push();
|
||||
this.radioButton(attr);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders an x/html submit input tag
|
||||
* @param {Object} param An object containing the tag attributes
|
||||
*/
|
||||
helma.Html.prototype.submit = function(param) {
|
||||
if (!param) {
|
||||
res.write("[Html.submit: insufficient arguments]");
|
||||
return;
|
||||
}
|
||||
var attr = Object.prototype.reduce.call(param);
|
||||
attr.type = "submit";
|
||||
if (!attr.name)
|
||||
attr.name = attr.type;
|
||||
attr.value = (attr.value != null) ? encodeForm(attr.value) : attr.type;
|
||||
this.tag("input", attr);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a rendered x/html submit input tag
|
||||
* @param {Object} attr An object containing the tag attributes
|
||||
* @returns The rendered submit input tag
|
||||
* @type String
|
||||
* @see #submit
|
||||
*/
|
||||
helma.Html.prototype.submitAsString = function(attr) {
|
||||
res.push();
|
||||
this.submit(attr);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders an x/html button input tag
|
||||
* @param {Object} param An object containing the tag attributes
|
||||
*/
|
||||
helma.Html.prototype.button = function(param) {
|
||||
if (!param) {
|
||||
res.write("[Html.button: insufficient arguments]");
|
||||
return;
|
||||
}
|
||||
var attr = Object.prototype.reduce.call(param);
|
||||
attr.type = "button";
|
||||
if (!attr.name)
|
||||
attr.name = attr.type;
|
||||
attr.value = (attr.value != null) ? encodeForm(attr.value) : attr.type;
|
||||
this.tag("input", attr);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a rendered x/html button input tag
|
||||
* @param {Object} param An object containing the tag attributes
|
||||
* @returns The rendered button input tag
|
||||
* @type String
|
||||
* @see #button
|
||||
*/
|
||||
helma.Html.prototype.buttonAsString = function(attr) {
|
||||
res.push();
|
||||
this.button(attr);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a x/html drop down select box
|
||||
* @param {Object} param An object containing the tag attributes
|
||||
* @param {Array} options Either an array of strings, an array with
|
||||
* several <code>{value: v, display: d}</code> objects, or a collection
|
||||
* of <code>["value", "display"]</code> arrays in an array
|
||||
* @param {String} selectedValue The value to pre-select
|
||||
* @param {String} firstOption An optional first option to display in the
|
||||
* select box (this option will always have no value)
|
||||
*/
|
||||
helma.Html.prototype.dropDown = function(param, options, selectedValue, firstOption) {
|
||||
if (!param) {
|
||||
res.write("[Html.dropDown: insufficient arguments]");
|
||||
return;
|
||||
}
|
||||
var attr = Object.prototype.reduce.call(param);
|
||||
if (!attr.size)
|
||||
attr.size = 1;
|
||||
this.openTag("select", attr);
|
||||
res.write("\n ");
|
||||
if (firstOption) {
|
||||
this.openTag("option", {value: ""});
|
||||
res.write(firstOption);
|
||||
this.closeTag("option");
|
||||
res.write("\n ");
|
||||
}
|
||||
for (var i in options) {
|
||||
var attr = new Object();
|
||||
var display = "";
|
||||
if ((options[i] instanceof Array) && options[i].length > 0) {
|
||||
// option is an array
|
||||
attr.value = options[i][0];
|
||||
display = options[i][1];
|
||||
} else if (options[i].value != null && options[i].display != null) {
|
||||
// option is an object
|
||||
attr.value = options[i].value;
|
||||
if (options[i]["class"] != null) {
|
||||
attr["class"] = options[i]["class"];
|
||||
}
|
||||
display = options[i].display;
|
||||
} else {
|
||||
// assume option is a string
|
||||
attr.value = i;
|
||||
display = options[i];
|
||||
}
|
||||
if (helma.Html.isSelected(attr.value, selectedValue))
|
||||
attr.selected = "selected";
|
||||
this.openTag("option", attr);
|
||||
res.write(display);
|
||||
this.closeTag("option");
|
||||
res.write("\n ");
|
||||
}
|
||||
this.closeTag("select");
|
||||
res.write("\n ");
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a rendered x/html drop down select box
|
||||
* @param {Object} param An object containing the tag attributes
|
||||
* @param {Array} options Either an array of strings, an array with
|
||||
* several <code>{value: v, display: d}</code> objects, or a collection
|
||||
* of <code>["value", "display"]</code> arrays in an array
|
||||
* @param {String} selectedValue The value to pre-select
|
||||
* @param {String} firstOption An optional first option to display in the
|
||||
* select box (this option will always have no value)
|
||||
* @returns The rendered drop down select box
|
||||
* @type String
|
||||
* @see #dropDown
|
||||
*/
|
||||
helma.Html.prototype.dropDownAsString = function(attr, options, selectedValue, firstOption) {
|
||||
res.push();
|
||||
this.dropDown(attr, options, selectedValue, firstOption);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders an image map based on an array containing the map parameters.
|
||||
* @param {String} name The name of the image map
|
||||
* @param {Array} param An array containing objects, where each of them
|
||||
* contains the attributes for a single image map entry
|
||||
*/
|
||||
helma.Html.prototype.map = function(name, param) {
|
||||
if (!name || !param) {
|
||||
res.write("[Html.map: insufficient arguments]");
|
||||
return;
|
||||
}
|
||||
this.openTag("map", {name: name});
|
||||
var attr = Object.prototype.reduce.call(param);
|
||||
for (var i in areas) {
|
||||
if (!areas[i].alt)
|
||||
areas[i].alt = "";
|
||||
if (!areas[i].shape)
|
||||
areas[i].shape = "rect";
|
||||
this.openTag("area", areas[i]);
|
||||
}
|
||||
this.closeTag("map");
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a rendered image map based on an array containing the map parameters.
|
||||
* @param {String} name The name of the image map
|
||||
* @param {Array} areas An array containing objects, where each of them
|
||||
* contains the attributes for a single image map entry
|
||||
* @returns The rendered image map
|
||||
* @type String
|
||||
* @see #map
|
||||
*/
|
||||
helma.Html.prototype.mapAsString = function(name, areas) {
|
||||
res.push();
|
||||
this.map(name, areas);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a complete x/html table.
|
||||
* @param {Array} headers An array containing table headers
|
||||
* @param {Array} data A two-dimensional array containing the table data
|
||||
* @param {Object} param An object containing the following properties:
|
||||
* <ul>
|
||||
* <li><code>table</code>: Attributes to render within the opening <code><table></code> tag</li>
|
||||
* <li><code>tr</code>: Attributes to render within each <code><tr></code> tag</li>
|
||||
* <li><code>td</code>: Attributes to render within each <code><td></code> tag</li>
|
||||
* <li><code>th</code>: Attributes to render within each <code><th></code> tag</li>
|
||||
* <li><code>trHead</code>: Attributes to render within each <code><tr></code> tag
|
||||
in the header area of the table</li>
|
||||
* <li><code>trEven</code>: Attributes to render within each even <code><tr></code> tag</li>
|
||||
* <li><code>trOdd</code>: Attributes to render within each odd <code><tr></code> tag</li>
|
||||
* <li><code>tdEven</code>: Attributes to render within each even <code><td></code> tag</li>
|
||||
* <li><code>tdOdd</code>: Attributes to render within each odd <code><td></code> tag</li>
|
||||
* <li><code>thEven</code>: Attributes to render within each even <code><th></code> tag</li>
|
||||
* <li><code>thOdd</code>: Attributes to render within each odd <code><th></code> tag</li>
|
||||
* </ul>
|
||||
*/
|
||||
helma.Html.prototype.table = function(headers, data, param) {
|
||||
if (!param) {
|
||||
res.write("[Html.table: insufficient arguments]");
|
||||
return;
|
||||
}
|
||||
var attr = Object.prototype.reduce.call(param);
|
||||
if (!attr.trHead) attr.trHead = attr.tr;
|
||||
if (!attr.trEven) attr.trEven = attr.tr;
|
||||
if (!attr.trOdd) attr.trOdd = attr.tr;
|
||||
if (!attr.tdEven) attr.tdEven = attr.td;
|
||||
if (!attr.tdOdd) attr.tdOdd = attr.td;
|
||||
if (!attr.thEven) attr.thEven = attr.th;
|
||||
if (!attr.thOdd) attr.thOdd = attr.th;
|
||||
this.openTag("table", attr.table);
|
||||
if (headers) {
|
||||
this.openTag("tr", attr.trHead);
|
||||
for (var i in headers) {
|
||||
var evenOdd = i % 2 == 0 ? "Even" : "Odd";
|
||||
this.openTag("th", attr["th"+evenOdd]);
|
||||
res.write(headers[i]);
|
||||
this.closeTag("th");
|
||||
}
|
||||
this.closeTag("tr");
|
||||
}
|
||||
for (var i in data) {
|
||||
var evenOdd = i % 2 == 0 ? "Even" : "Odd";
|
||||
this.openTag("tr", attr["tr"+evenOdd]);
|
||||
for (var j in data[i]) {
|
||||
var evenOddCell = j % 2 == 0 ? "Even" : "Odd";
|
||||
this.openTag("td", attr["td"+evenOddCell]);
|
||||
res.write(data[i][j]);
|
||||
this.closeTag("td");
|
||||
}
|
||||
this.closeTag("tr");
|
||||
}
|
||||
this.closeTag("table");
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a rendered x/html table
|
||||
* @param {Array} headers An array containing table headers
|
||||
* @param {Array} data A two-dimensional array containing the table data
|
||||
* @param {Object} attr For a description see {@link #table}
|
||||
* @returns The rendered table
|
||||
* @type String
|
||||
* @see #table
|
||||
*/
|
||||
helma.Html.prototype.tableAsString = function(headers, data, attr) {
|
||||
res.push();
|
||||
this.table(headers, data, attr);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/*********************************************************************/
|
||||
/* */
|
||||
/* the following functions should be deliberately altered or removed */
|
||||
/* (most of these can easily be replaced by the methods they call) */
|
||||
/* */
|
||||
/*********************************************************************/
|
||||
|
||||
/**
|
||||
* Renders an x/html opening link tag
|
||||
* @param {Object} attr An object containing the tag attributes
|
||||
*/
|
||||
helma.Html.prototype.openLink = function(attr) {
|
||||
this.openTag("a", attr);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an x/html opening link tag
|
||||
* @param {Object} attr An object containing the tag attributes
|
||||
* @returns The rendered open link tag
|
||||
* @type String
|
||||
* @see #openTag
|
||||
*/
|
||||
helma.Html.prototype.openLinkAsString = function(attr) {
|
||||
return this.openTagAsString("a", attr);
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders an x/html closing link tag
|
||||
*/
|
||||
helma.Html.prototype.closeLink = function() {
|
||||
this.closeTag("a");
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a rendered x/html closing link tag
|
||||
* @returns Rhe rendered closing link tag
|
||||
* @type String
|
||||
* @see #closeLink
|
||||
*/
|
||||
helma.Html.prototype.closeLinkAsString = function() {
|
||||
return this.closeTagAsString("a");
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a color definition string. If the string passed as
|
||||
* argument contains only hex characters it will be prefixed with a
|
||||
* hash sign if necessary, otherwise this method assumes that the
|
||||
* value is a named color (eg. "yellow").
|
||||
* @param {String} c The color definintion
|
||||
* @deprecated
|
||||
*/
|
||||
helma.Html.prototype.color = function(c) {
|
||||
if (c) {
|
||||
var nonhex = /[^0-9,a-f]/gi;
|
||||
if (!c.match(nonhex)) {
|
||||
c = c.pad("0", 6);
|
||||
res.write("#");
|
||||
}
|
||||
}
|
||||
res.write(c);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a color definition.
|
||||
* @param {String} c The color definintion
|
||||
* @returns The rendered color definition
|
||||
* @type String
|
||||
* @see #color
|
||||
* @deprecated
|
||||
*/
|
||||
helma.Html.prototype.colorAsString = function(c) {
|
||||
res.push();
|
||||
this.color(c);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders an x/html opening form tag
|
||||
* @param {Object} attr An object containing the tag attributes
|
||||
*/
|
||||
helma.Html.prototype.form = function(attr) {
|
||||
this.openTag("form", attr);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an x/html opening form tag
|
||||
* @param {Object} attr An object containing the tag attributes
|
||||
* @returns The rendered opening form tag
|
||||
* @type String
|
||||
* @see #form
|
||||
*/
|
||||
helma.Html.prototype.formAsString = function(attr) {
|
||||
res.push();
|
||||
this.form(attr);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders an x/html password input tag
|
||||
* @param {Object} attr An object containing the tag attributes
|
||||
*/
|
||||
helma.Html.prototype.password = function(attr) {
|
||||
if (!attr) {
|
||||
res.write("[Html.password: insufficient arguments]");
|
||||
return;
|
||||
}
|
||||
attr.type = "password";
|
||||
if (!attr.size)
|
||||
attr.size = 20;
|
||||
this.tag("input", attr);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a rendered x/html password input tag
|
||||
* @param {Object} attr An object containing the tag attributes
|
||||
* @returns The rendered password input tag
|
||||
* @type String
|
||||
* @see #password
|
||||
*/
|
||||
helma.Html.prototype.passwordAsString = function(attr) {
|
||||
res.push();
|
||||
this.password(attr);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders an x/html file input tag
|
||||
* @param {Object} attr An object containing the tag attributes
|
||||
*/
|
||||
helma.Html.prototype.file = function(attr) {
|
||||
if (!attr) {
|
||||
res.write("[Html.file: insufficient arguments]");
|
||||
return;
|
||||
}
|
||||
attr.type = "file";
|
||||
this.tag("input", attr);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a rendered x/html file input tag
|
||||
* @param {Object} attr An object containing the tag attributes
|
||||
* @returns The rendered file input tag
|
||||
* @type String
|
||||
* @see #file
|
||||
*/
|
||||
helma.Html.prototype.fileAsString = function(attr) {
|
||||
res.push();
|
||||
this.file(attr);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses the string passed as argument and converts any
|
||||
* URL in it into a link tag
|
||||
* @param {String} str The string wherein URLs should be
|
||||
* converted into link tags
|
||||
* @returns The string containing URLs converted into link tags
|
||||
* @type String
|
||||
*/
|
||||
helma.Html.prototype.activateUrls = function(str) {
|
||||
var re = /(^|\/>|\s+)([fhtpsr]+:\/\/[^\s]+?)([\.,;:\)\]\"]?)(?=[\s<]|$)/gim;
|
||||
var func = function(str, p1, p2, p3) {
|
||||
res.push();
|
||||
res.write(p1);
|
||||
res.write('<a href="');
|
||||
res.write(p2);
|
||||
res.write('">');
|
||||
res.write(p2.clip(50, "...", true));
|
||||
res.write('</a>');
|
||||
res.write(p3);
|
||||
return res.pop();
|
||||
};
|
||||
return str.replace(re, func);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new TableWriter instance
|
||||
* @class This class provides various methods for
|
||||
* programmatically creating an x/html table.
|
||||
* @param {Number} numberOfColumns The number of columns in the table
|
||||
* @param {Object} attr An object containing attributes to use when
|
||||
* rendering the single table elements. For a description see {@link #table}.
|
||||
* @returns An instance of TableWriter
|
||||
* @constructor
|
||||
*/
|
||||
helma.Html.TableWriter = function(numberOfColumns, attr) {
|
||||
if (isNaN(numberOfColumns))
|
||||
throw "Illegal argument in TableWriter(): first argument must be a number";
|
||||
if (numberOfColumns < 1)
|
||||
throw "Illegal argument in TableWriter(): first argument must be > 1";
|
||||
/** @private */
|
||||
this.ncols = numberOfColumns;
|
||||
/** @private */
|
||||
this.written = 0;
|
||||
// if no attributes object given, create an empty one
|
||||
if (!attr)
|
||||
attr = {};
|
||||
if (!attr.trEven) attr.trEven = attr.tr;
|
||||
if (!attr.trOdd) attr.trOdd = attr.tr;
|
||||
if (!attr.trHead) attr.trHead = attr.trEven;
|
||||
if (!attr.tdEven) attr.tdEven = attr.td;
|
||||
if (!attr.tdOdd) attr.tdOdd = attr.td;
|
||||
if (!attr.thEven) attr.thEven = attr.th;
|
||||
if (!attr.thOdd) attr.thOdd = attr.th;
|
||||
/** @private */
|
||||
this.attr = attr;
|
||||
|
||||
/**
|
||||
* If set to true the first row of the table data is rendered
|
||||
* using <code><th></code> tags (defaults to false).
|
||||
* @type Boolean
|
||||
*/
|
||||
this.writeHeader = false;
|
||||
|
||||
/**
|
||||
* If set to true the TableWriter returns the rendered table
|
||||
* as string, otherwise the table is written directly to response,
|
||||
* which is the default.
|
||||
* @type Boolean
|
||||
*/
|
||||
this.writeString = false;
|
||||
|
||||
this.dontEnum("ncols", "written", "attr", "writeHeader", "writeString");
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
helma.Html.TableWriter.prototype.toString = function() {
|
||||
return "[helma.Html.TableWriter]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a single table cell to response.
|
||||
* @param {String} text The content of the table cess
|
||||
* @param {Object} attr An optional object containig attributes
|
||||
* to render for this table cell
|
||||
*/
|
||||
helma.Html.TableWriter.prototype.write = function(text, attr) {
|
||||
// set up some variables
|
||||
var isHeaderRow = (this.writeHeader && this.written < this.ncols);
|
||||
var isNewRow = (this.written % this.ncols == 0);
|
||||
var isEvenRow = ((this.written / this.ncols) % 2 == 0);
|
||||
var isEvenCol = ((this.written % this.ncols) % 2 == 0);
|
||||
// write out table and table row tags
|
||||
if (this.written == 0) {
|
||||
if (this.writeString)
|
||||
res.push();
|
||||
helma.Html.prototype.openTag.call(this, "table", this.attr.table);
|
||||
helma.Html.prototype.openTag.call(this, "tr", this.attr.trHead);
|
||||
} else if (isNewRow) {
|
||||
helma.Html.prototype.closeTag.call(this, "tr");
|
||||
if (isEvenRow)
|
||||
helma.Html.prototype.openTag.call(this, "tr", this.attr.trEven);
|
||||
else
|
||||
helma.Html.prototype.openTag.call(this, "tr", this.attr.trOdd);
|
||||
}
|
||||
// get the attribute object for the table cell
|
||||
if (!attr) {
|
||||
// no explicit attribute given
|
||||
if (isEvenCol) {
|
||||
attr = isHeaderRow ? this.attr.thEven : this.attr.tdEven;
|
||||
} else {
|
||||
attr = isHeaderRow ? this.attr.thOdd : this.attr.tdOdd;
|
||||
}
|
||||
}
|
||||
// write out table cell tag
|
||||
helma.Html.prototype.openTag.call(this, isHeaderRow ? "th" : "td", attr);
|
||||
// write out table cell contents
|
||||
if (text) {
|
||||
res.write(text);
|
||||
}
|
||||
// close table cell
|
||||
helma.Html.prototype.closeTag.call(this, isHeaderRow ? "th" : "td");
|
||||
if (attr && !isNaN(attr.colspan)) {
|
||||
this.written += attr.colspan;
|
||||
} else {
|
||||
this.written += 1;
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Closes all open table tags. If {@link #writeString} is set to
|
||||
* true, this method returns the rendered table.
|
||||
* @returns The rendered table, if {@link #writeString} is set to
|
||||
* true, otherwise void.
|
||||
* @type String
|
||||
*/
|
||||
helma.Html.TableWriter.prototype.close = function() {
|
||||
if (this.written > 0) {
|
||||
while (this.written++ % this.ncols != 0)
|
||||
res.write("<td></td>");
|
||||
res.write("</tr></table>");
|
||||
this.written = 0;
|
||||
}
|
||||
if (this.writeString)
|
||||
return res.pop();
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
|
||||
helma.lib = "Html";
|
||||
helma.dontEnum(helma.lib);
|
||||
for (var i in helma[helma.lib])
|
||||
helma[helma.lib].dontEnum(i);
|
||||
for (var i in helma[helma.lib].prototype)
|
||||
helma[helma.lib].prototype.dontEnum(i);
|
||||
for (var i in helma[helma.lib].TableWriter.prototype)
|
||||
helma[helma.lib].TableWriter.prototype.dontEnum(i);
|
||||
delete helma.lib;
|
817
modules/helma/Http.js
Normal file
817
modules/helma/Http.js
Normal file
|
@ -0,0 +1,817 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Http.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the helma.Http class.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/helma/Http.js')
|
||||
*/
|
||||
|
||||
// take care of any dependencies
|
||||
app.addRepository('modules/core/Date.js');
|
||||
|
||||
|
||||
/**
|
||||
* Define the global namespace if not existing
|
||||
*/
|
||||
if (!global.helma) {
|
||||
global.helma = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of helma.Http
|
||||
* @class This class provides functionality to programatically issue
|
||||
* an Http request based on java.net.HttpUrlConnection.
|
||||
* By default the request will use method <code>GET</code>.
|
||||
* @returns A newly created helma.Http instance
|
||||
* @constructor
|
||||
*/
|
||||
helma.Http = function() {
|
||||
var self = this;
|
||||
var proxy = null;
|
||||
var content = "";
|
||||
var userAgent = "Helma Http Client";
|
||||
var method = "GET";
|
||||
var cookies = null;
|
||||
var credentials = null;
|
||||
var followRedirects = true;
|
||||
var binaryMode = false;
|
||||
var headers = {};
|
||||
var timeout = {
|
||||
"connect": 0,
|
||||
"socket": 0
|
||||
};
|
||||
var maxResponseSize = null;
|
||||
|
||||
var responseHandler = function(connection, result) {
|
||||
var input;
|
||||
try {
|
||||
input = new java.io.BufferedInputStream(connection.getInputStream());
|
||||
} catch (error) {
|
||||
input = new java.io.BufferedInputStream(connection.getErrorStream());
|
||||
}
|
||||
if (input) {
|
||||
var body = new java.io.ByteArrayOutputStream();
|
||||
var buf = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 1024);
|
||||
var len;
|
||||
var currentSize = 0;
|
||||
while ((len = input.read(buf)) > -1) {
|
||||
body.write(buf, 0, len);
|
||||
currentSize += len;
|
||||
if (maxResponseSize && currentSize > maxResponseSize) {
|
||||
throw new Error("Maximum allowed response size is exceeded");
|
||||
}
|
||||
}
|
||||
try {
|
||||
input.close();
|
||||
} catch (error) {
|
||||
// safe to ignore
|
||||
}
|
||||
if (binaryMode && (result.code >= 200 && result.code < 300)) {
|
||||
// only honor binaryMode if the request succeeded
|
||||
result.content = body.toByteArray();
|
||||
} else {
|
||||
result.content = result.charset ?
|
||||
body.toString(result.charset) :
|
||||
body.toString();
|
||||
}
|
||||
// adjust content length
|
||||
if (result.content) {
|
||||
result.length = result.content.length;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** @private */
|
||||
var setTimeout = function(type, value) {
|
||||
var v = java.lang.System.getProperty("java.specification.version");
|
||||
if (parseFloat(v, 10) >= 1.5) {
|
||||
timeout[type] = value;
|
||||
} else {
|
||||
app.logger.warn("helma.Http: Timeouts can only be set with Java Runtime version >= 1.5");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the proxy host and port for later use. The argument must
|
||||
* be in <code>host:port</code> format (eg. "proxy.example.com:3128").
|
||||
* @param {String} proxyString The proxy to use for this request
|
||||
* @see #getProxy
|
||||
*/
|
||||
this.setProxy = function(proxyString) {
|
||||
var idx = proxyString.indexOf(":");
|
||||
var host = proxyString.substring(0, idx);
|
||||
var port = proxyString.substring(idx+1);
|
||||
if (java.lang.Class.forName("java.net.Proxy") != null) {
|
||||
// construct a proxy instance
|
||||
var socket = new java.net.InetSocketAddress(host, port);
|
||||
proxy = new java.net.Proxy(java.net.Proxy.Type.HTTP, socket);
|
||||
} else {
|
||||
// the pre jdk1.5 way: set the system properties
|
||||
var sys = java.lang.System.getProperties();
|
||||
if (host) {
|
||||
app.logger.warn("[Helma Http Client] WARNING: setting system http proxy to " + host + ":" + port);
|
||||
sys.put("http.proxySet", "true");
|
||||
sys.put("http.proxyHost", host);
|
||||
sys.put("http.proxyPort", port);
|
||||
}
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the proxy in <code>host:port</code> format
|
||||
* @return The proxy defined for this request
|
||||
* @type String
|
||||
* @see #setProxy
|
||||
*/
|
||||
this.getProxy = function() {
|
||||
if (proxy != null) {
|
||||
return proxy.address().getHostName() + ":" + proxy.address().getPort();
|
||||
} else if (sys.get("http.proxySet") == "true") {
|
||||
return sys.get("http.proxyHost") + ":" + sys.get("http.proxyPort");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the credentials for basic http authentication
|
||||
* @param {String} username The username
|
||||
* @param {String} password The password
|
||||
*/
|
||||
this.setCredentials = function(username, password) {
|
||||
var str = new java.lang.String(username + ":" + password);
|
||||
credentials = (new Packages.sun.misc.BASE64Encoder()).encode(str.getBytes());
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content to send to the remote server within this request.
|
||||
* @param {String|Object} stringOrObject The content of the request, which
|
||||
* can be either a string or an object. In the latter case all properties
|
||||
* and their values are concatenated into a single string.
|
||||
* If a property is an array, then for each value the propertyname and value pair is added.
|
||||
* If the name of an array property ends with "_array" then the _array part is removed.
|
||||
*/
|
||||
this.setContent = function(stringOrObject) {
|
||||
if (stringOrObject != null) {
|
||||
if (stringOrObject.constructor == Object) {
|
||||
res.push();
|
||||
var value;
|
||||
for (var key in stringOrObject) {
|
||||
value = stringOrObject[key];
|
||||
if (value instanceof Array) {
|
||||
if (key.substring(key.length - 6) == "_array")
|
||||
key = key.substring(0,key.length - 6);
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
res.write(encodeURIComponent(key));
|
||||
res.write("=");
|
||||
res.write(encodeURIComponent(value[i]));
|
||||
res.write("&");
|
||||
}
|
||||
} else {
|
||||
res.write(encodeURIComponent(key));
|
||||
res.write("=");
|
||||
res.write(encodeURIComponent(value));
|
||||
res.write("&");
|
||||
}
|
||||
}
|
||||
content = res.pop();
|
||||
content = content.substring(0, content.length-1);
|
||||
} else {
|
||||
content = stringOrObject.toString();
|
||||
}
|
||||
} else {
|
||||
content = null;
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the request method to use.
|
||||
* @param {String} m The method to use (<code>GET</code>, <code>POST</code> ...)
|
||||
* @see #getMethod
|
||||
*/
|
||||
this.setMethod = function(m) {
|
||||
method = m;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the currently defined request method.
|
||||
* @returns The method used
|
||||
* @type String
|
||||
* @see #setMethod
|
||||
*/
|
||||
this.getMethod = function() {
|
||||
return method;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets a single HTTP request header field
|
||||
* @param {String} name The name of the header field
|
||||
* @param {String} value The value of the header field
|
||||
* @see #getHeader
|
||||
*/
|
||||
this.setHeader = function(name, value) {
|
||||
headers[name] = value;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the value of the request header field with the given name
|
||||
* @param {String} name The name of the request header field
|
||||
* @returns The value of the request header field
|
||||
* @type String
|
||||
* @see #setHeader
|
||||
*/
|
||||
this.getHeader = function(name) {
|
||||
return headers[name];
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a cookie with the name and value passed as arguments
|
||||
* to the list of cookies to send to the remote server.
|
||||
* @param {String} name The name of the cookie
|
||||
* @param {String} value The value of the cookie
|
||||
* @see #getCookie
|
||||
* @see #getCookies
|
||||
*/
|
||||
this.setCookie = function(name, value) {
|
||||
if (name != null && value != null) {
|
||||
// store the cookie in the cookies map
|
||||
if (!cookies) {
|
||||
cookies = {};
|
||||
}
|
||||
cookies[name] = new helma.Http.Cookie(name, value);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the value of the cookie with the given name
|
||||
* @param {String} name The name of the cookie
|
||||
* @returns The value of the cookie
|
||||
* @type String
|
||||
* @see #setCookie
|
||||
*/
|
||||
this.getCookie = function(name) {
|
||||
return (cookies != null) ? cookies[name] : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds the cookies passed as argument to the list of cookies to send
|
||||
* to the remote server.
|
||||
* @param {Array} cookies An array containing objects with the properties
|
||||
* "name" (the name of the cookie) and "value" (the value of the cookie) set.
|
||||
*/
|
||||
this.setCookies = function(cookies) {
|
||||
if (cookies != null) {
|
||||
for (var i=0; i<cookies.length; i++) {
|
||||
this.setCookie(cookies[i].name, cookies[i].value);
|
||||
}
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns all cookies set for this client
|
||||
* @return An object containing all cookies, where the property
|
||||
* name is the name of the cookie, and the value is the cookie value
|
||||
* @see #setCookie
|
||||
*/
|
||||
this.getCookies = function() {
|
||||
return cookies;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the connection timeout to the amount of milliseconds
|
||||
* passed as argument
|
||||
* @param {Number} timeout The connection timeout in milliseconds
|
||||
* @see #getTimeout
|
||||
*/
|
||||
this.setTimeout = function(timeout) {
|
||||
setTimeout("connect", timeout);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the read timeout (the maximum time a request may take after
|
||||
* the connection has been successfully established) to the amount of
|
||||
* milliseconds passed as argument.
|
||||
* @param {Number} timeout The read timeout in milliseconds
|
||||
* @see #getReadTimeout
|
||||
*/
|
||||
this.setReadTimeout = function(timeout) {
|
||||
setTimeout("socket", timeout);
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the connection timeout
|
||||
* @returns The connection timeout in milliseconds
|
||||
* @type Number
|
||||
* @see #setTimeout
|
||||
*/
|
||||
this.getTimeout = function() {
|
||||
return timeout.connect;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the read timeout (the maximum time a request may take after
|
||||
* the connection has been successfully established).
|
||||
* @returns The read timeout in milliseconds
|
||||
* @type Number
|
||||
* @see #setReadTimeout
|
||||
*/
|
||||
this.getReadTimeout = function() {
|
||||
return timeout.socket;
|
||||
};
|
||||
|
||||
/**
|
||||
* Enables or disables following redirects
|
||||
* @param {Boolean} value If false this client won't follow redirects (the default is
|
||||
* to follow them)
|
||||
* @see #getFollowRedirects
|
||||
*/
|
||||
this.setFollowRedirects = function(value) {
|
||||
followRedirects = value;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the client follows redirects
|
||||
* @returns True if the client follows redirects, false otherwise.
|
||||
* @see #setFollowRedirects
|
||||
*/
|
||||
this.getFollowRedirects = function() {
|
||||
return followRedirects;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the HTTP "User-Agent" header field to the string passed as argument
|
||||
* @param {String} agent The string to use as value of the
|
||||
* "User-Agent" header field (defaults to "Helma Http Client")
|
||||
* @see #getUserAgent
|
||||
*/
|
||||
this.setUserAgent = function(agent) {
|
||||
userAgent = agent;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the value of the HTTP "User-Agent" header field
|
||||
* @returns The value of the field
|
||||
* @type String
|
||||
* @see #setUserAgent
|
||||
*/
|
||||
this.getUserAgent = function() {
|
||||
return userAgent;
|
||||
};
|
||||
|
||||
/**
|
||||
* Switches content text encoding on or off. Depending on this
|
||||
* the content received from the remote server will be either a
|
||||
* string or a byte array.
|
||||
* @param {Boolean} mode If true binary mode is activated
|
||||
* @see #getBinaryMode
|
||||
*/
|
||||
this.setBinaryMode = function(mode) {
|
||||
binaryMode = mode;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the currently defined binary mode of this client
|
||||
* @returns The binary mode of this client
|
||||
* @type Boolean
|
||||
* @see #setBinaryMode
|
||||
*/
|
||||
this.getBinaryMode = function() {
|
||||
return binaryMode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the max allowed size for the response stream
|
||||
* @param {Integer} Size in Byte
|
||||
*/
|
||||
this.setMaxResponseSize = function(size) {
|
||||
maxResponseSize = size;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the currently set max response size
|
||||
* @returns The max responsesize
|
||||
* @type Integer
|
||||
* @see #setMaxResponseSize
|
||||
*/
|
||||
this.getMaxResponseSize = function() {
|
||||
return maxResponseSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* Overloads the default response handler.
|
||||
* Use this do implement your own response handling, like storing the response directly to the harddisk
|
||||
* The handler function gets two parameter, first is the java.net.URLConnection and second is the result object.
|
||||
* Note that custom response handler functions should check the HTTP status code before reading
|
||||
* the response. The status code for successful requests is 200. Response bodies for requests with
|
||||
* status codes less than 400 can be read from the connection's input stream, while response bodies
|
||||
* with 4xx or 5xx status codes must be read using the error stream.
|
||||
* @param {function} Response handler function
|
||||
*/
|
||||
this.setResponseHandler = function(callback) {
|
||||
responseHandler = callback;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the response handler. This is the function used to read the HTTP response body.
|
||||
* @returns The response handler function
|
||||
*/
|
||||
this.getResponseHandler = function() {
|
||||
return responseHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a http request
|
||||
* @param {String} url The url to request
|
||||
* @param {Date|String} opt If this argument is a string, it is used
|
||||
* as value for the "If-None-Match" request header field. If it is a
|
||||
* Date instance it is used as "IfModifiedSince" condition for this request.
|
||||
* @return A result object containing the following properties:
|
||||
* <ul>
|
||||
* <li><code>url</code>: (String) The Url of the request</li>
|
||||
* <li><code>location</code>: (String) The value of the location header field</li>
|
||||
* <li><code>code</code>: (Number) The HTTP response code</li>
|
||||
* <li><code>message</code>: (String) An optional HTTP response message</li>
|
||||
* <li><code>length</code>: (Number) The content length of the response</li>
|
||||
* <li><code>type</code>: (String) The mimetype of the response</li>
|
||||
* <li><code>charset</code>: (String) The character set of the response</li>
|
||||
* <li><code>encoding</code>: (String) An optional encoding to use with the response</li>
|
||||
* <li><code>lastModified</code>: (String) The value of the lastModified response header field</li>
|
||||
* <li><code>eTag</code>: (String) The eTag as received from the remote server</li>
|
||||
* <li><code>cookie</code>: (helma.Http.Cookie) An object containing the cookie parameters, if the remote
|
||||
server has set the "Set-Cookie" header field</li>
|
||||
* <li><code>headers</code>: (java.util.Map) A map object containing the headers, access them using get("headername")
|
||||
* <li><code>content</code>: (String|ByteArray) The response received from the server. Can be either
|
||||
a string or a byte array (see #setBinaryMode)</li>
|
||||
* </ul>
|
||||
*/
|
||||
this.getUrl = function(url, opt) {
|
||||
if (typeof url == "string") {
|
||||
if (!(url = helma.Http.evalUrl(url)))
|
||||
throw new Error("'" + url + "' is not a valid URL.");
|
||||
} else if (!(url instanceof java.net.URL)) {
|
||||
throw new Error("'" + url + "' is not a valid URL.");
|
||||
}
|
||||
|
||||
var conn = proxy ? url.openConnection(proxy) : url.openConnection();
|
||||
// Note: we must call setInstanceFollowRedirects() instead of
|
||||
// static method setFollowRedirects(), as the latter will
|
||||
// set the default value for all url connections, and will not work for
|
||||
// url connections that have already been created.
|
||||
conn.setInstanceFollowRedirects(followRedirects);
|
||||
conn.setAllowUserInteraction(false);
|
||||
conn.setRequestMethod(method);
|
||||
conn.setRequestProperty("User-Agent", userAgent);
|
||||
|
||||
if (opt) {
|
||||
if (opt instanceof Date)
|
||||
conn.setIfModifiedSince(opt.getTime());
|
||||
else if ((typeof opt == "string") && (opt.length > 0))
|
||||
conn.setRequestProperty("If-None-Match", opt);
|
||||
}
|
||||
|
||||
var userinfo;
|
||||
if (userinfo = url.getUserInfo()) {
|
||||
userinfo = userinfo.split(/:/, 2);
|
||||
this.setCredentials(userinfo[0], userinfo[1]);
|
||||
}
|
||||
if (credentials != null) {
|
||||
conn.setRequestProperty("Authorization", "Basic " + credentials);
|
||||
}
|
||||
// set timeouts
|
||||
if (parseFloat(java.lang.System.getProperty("java.specification.version"), 10) >= 1.5) {
|
||||
conn.setConnectTimeout(timeout.connect);
|
||||
conn.setReadTimeout(timeout.socket);
|
||||
}
|
||||
// set header fields
|
||||
for (var i in headers) {
|
||||
conn.setRequestProperty(i, headers[i]);
|
||||
}
|
||||
// set cookies
|
||||
if (cookies != null) {
|
||||
var arr = [];
|
||||
for (var i in cookies) {
|
||||
arr[arr.length] = cookies[i].getFieldValue();
|
||||
}
|
||||
conn.setRequestProperty("Cookie", arr.join(";"));
|
||||
}
|
||||
// set content
|
||||
if (content) {
|
||||
conn.setRequestProperty("Content-Length", content.length);
|
||||
conn.setDoOutput(true);
|
||||
var out = new java.io.OutputStreamWriter(conn.getOutputStream());
|
||||
out.write(content);
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
|
||||
var result = {
|
||||
url: conn.getURL(),
|
||||
location: conn.getHeaderField("location"),
|
||||
code: conn.getResponseCode(),
|
||||
message: conn.getResponseMessage(),
|
||||
length: conn.getContentLength(),
|
||||
type: conn.getContentType(),
|
||||
encoding: conn.getContentEncoding(),
|
||||
lastModified: null,
|
||||
eTag: conn.getHeaderField("ETag"),
|
||||
cookies: null,
|
||||
headers: conn.getHeaderFields(),
|
||||
content: null,
|
||||
}
|
||||
|
||||
// parse all "Set-Cookie" header fields into an array of
|
||||
// helma.Http.Cookie instances
|
||||
var setCookies = conn.getHeaderFields().get("Set-Cookie");
|
||||
if (setCookies != null) {
|
||||
var arr = [];
|
||||
var cookie;
|
||||
for (var i=0; i<setCookies.size(); i++) {
|
||||
if ((cookie = helma.Http.Cookie.parse(setCookies.get(i))) != null) {
|
||||
arr.push(cookie);
|
||||
}
|
||||
}
|
||||
if (arr.length > 0) {
|
||||
result.cookies = arr;
|
||||
}
|
||||
}
|
||||
|
||||
var lastmod = conn.getLastModified();
|
||||
if (lastmod) {
|
||||
result.lastModified = new Date(lastmod);
|
||||
}
|
||||
|
||||
if (maxResponseSize && result.length > maxResponseSize) {
|
||||
throw new Error("Maximum allowed response size is exceeded");
|
||||
}
|
||||
|
||||
if (result.type && result.type.indexOf("charset=") != -1) {
|
||||
var charset = result.type.substring(result.type.indexOf("charset=") + 8);
|
||||
charset = charset.replace(/[;"]/g, '').trim();
|
||||
result.charset = charset;
|
||||
}
|
||||
|
||||
// invoke response handler
|
||||
responseHandler(conn, result);
|
||||
|
||||
conn.disconnect();
|
||||
return result;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
this.toString = function() {
|
||||
return "[Helma Http Client]";
|
||||
};
|
||||
|
||||
for (var i in this)
|
||||
this.dontEnum(i);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Evaluates the url passed as argument.
|
||||
* @param {String} url The url or uri string to evaluate
|
||||
* @returns If the argument is a valid url, this method returns
|
||||
* a new instance of java.net.URL, otherwise it returns null.
|
||||
* @type java.net.URL
|
||||
*/
|
||||
helma.Http.evalUrl = function(url) {
|
||||
try {
|
||||
return new java.net.URL(url);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the global http proxy setting. If no proxy definition
|
||||
* is passed to this method, any existing proxy setting is
|
||||
* cleared. Internally this method sets the system properties
|
||||
* <code>http.proxySet</code>, <code>http.proxyHost</code> and
|
||||
* <code>http.proxyPort</code>. Keep in mind that this is valid for
|
||||
* the whole Java Virtual Machine, therefor using this method
|
||||
* can potentially influence other running Helma applications too!
|
||||
* @param {String} proxyString A proxy definition in <code>host:port</code>
|
||||
* format (eg. "proxy.example.com:3128");
|
||||
* @member helma.Http
|
||||
*/
|
||||
helma.Http.setProxy = function(proxyString) {
|
||||
var sys = java.lang.System.getProperties();
|
||||
if (proxyString) {
|
||||
var idx = proxyString.indexOf(":");
|
||||
var host = proxyString.substring(0, idx);
|
||||
var port = proxyString.substring(idx+1);
|
||||
if (!port)
|
||||
port = "3128";
|
||||
else if (typeof port == "number")
|
||||
port = port.toString();
|
||||
app.logger.info("helma.Http.setProxy " + proxyString);
|
||||
sys.put("http.proxySet", "true");
|
||||
sys.put("http.proxyHost", host);
|
||||
sys.put("http.proxyPort", port);
|
||||
} else {
|
||||
sys.put("http.proxySet", "false");
|
||||
sys.put("http.proxyHost", "");
|
||||
sys.put("http.prodyPort", "");
|
||||
}
|
||||
return;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the proxy setting of the Java Virtual Machine
|
||||
* the Helma application server is running in. If no
|
||||
* proxy is set, this method returns boolean false.
|
||||
* @returns The global proxy setting in <code>host:port</code>
|
||||
* format (eg. "proxy.example.com:3128"), or boolean false.
|
||||
* @type String|Boolean
|
||||
* @member helma.Http
|
||||
*/
|
||||
helma.Http.getProxy = function() {
|
||||
var sys = java.lang.System.getProperties();
|
||||
if (sys.get("http.proxySet") == "true")
|
||||
return sys.get("http.proxyHost") + ":" + sys.get("http.proxyPort");
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static helper method to check if a request issued agains a
|
||||
* Helma application is authorized or not.
|
||||
* @param {String} name The username to check req.username against
|
||||
* @param {String} pwd The password to check req.password against
|
||||
* @return True if the request is authorized, false otherwise. In
|
||||
* the latter case the current response is reset and the response code
|
||||
* is set to "401" ("Authentication required").
|
||||
* @type Boolean
|
||||
*/
|
||||
helma.Http.isAuthorized = function(name, pwd) {
|
||||
if (!req.username || !req.password ||
|
||||
req.username != name || req.password != pwd) {
|
||||
res.reset();
|
||||
res.status = 401;
|
||||
res.realm = "Helma Http Authorization";
|
||||
res.write("Authorization required.");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
helma.Http.toString = function() {
|
||||
return "[helma.Http]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new instance of helma.Http.Cookie
|
||||
* @class Instances of this object represent a HTTP cookie
|
||||
* @param {String} name The name of the cookie
|
||||
* @param {String} value The value of the cookie
|
||||
* @returns A newly created Cookie instance
|
||||
* @constructor
|
||||
*/
|
||||
helma.Http.Cookie = function(name, value) {
|
||||
/**
|
||||
* The name of the Cookie
|
||||
* @type String
|
||||
*/
|
||||
this.name = name;
|
||||
|
||||
/**
|
||||
* The value of the Cookie
|
||||
* @type String
|
||||
*/
|
||||
this.value = value;
|
||||
|
||||
/**
|
||||
* An optional date defining the lifetime of this cookie
|
||||
* @type Date
|
||||
*/
|
||||
this.expires = null;
|
||||
|
||||
/**
|
||||
* An optional path where this cookie is valid
|
||||
* @type String
|
||||
*/
|
||||
this.path = null;
|
||||
|
||||
/**
|
||||
* An optional domain where this cookie is valid
|
||||
* @type String
|
||||
*/
|
||||
this.domain = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* An instance of java.text.SimpleDateFormat used for both parsing
|
||||
* an "expires" string into a date and vice versa
|
||||
* @type java.text.SimpleDateFormat
|
||||
* @final
|
||||
*/
|
||||
helma.Http.Cookie.DATEFORMAT = new java.text.SimpleDateFormat("EEE, dd-MMM-yy HH:mm:ss z");
|
||||
|
||||
|
||||
/**
|
||||
* A regular expression used for parsing cookie strings
|
||||
* @type RegExp
|
||||
* @final
|
||||
*/
|
||||
helma.Http.Cookie.PATTERN = /([^=;]+)=?([^;]*)(?:;\s*|$)/g;
|
||||
|
||||
|
||||
/**
|
||||
* Parses the cookie string passed as argument into an instance of helma.Http
|
||||
* @param {String} cookieStr The cookie string as received from the remote server
|
||||
* @returns An instance of helma.Http.Cookie containing the cookie parameters
|
||||
* @type helma.Http.Cookie
|
||||
*/
|
||||
helma.Http.Cookie.parse = function(cookieStr) {
|
||||
if (cookieStr != null) {
|
||||
var cookie = new helma.Http.Cookie;
|
||||
var m = helma.Http.Cookie.PATTERN.exec(cookieStr);
|
||||
if (m) {
|
||||
cookie.name = m[1].trim();
|
||||
cookie.value = m[2] ? m[2].trim() : "";
|
||||
}
|
||||
while ((m = helma.Http.Cookie.PATTERN.exec(cookieStr)) != null) {
|
||||
var key = m[1].trim();
|
||||
var value = m[2] ? m[2].trim() : "";
|
||||
switch (key.toLowerCase()) {
|
||||
case "expires":
|
||||
// try to parse the expires date string into a date object
|
||||
try {
|
||||
cookie.expires = helma.Http.Cookie.DATEFORMAT.parse(value);
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cookie[key.toLowerCase()] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cookie;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns this cookie in a format useable to set the HTTP header field "Cookie"
|
||||
* @return This cookie formatted as HTTP header field value
|
||||
* @type String
|
||||
*/
|
||||
helma.Http.Cookie.prototype.getFieldValue = function() {
|
||||
return this.name + "=" + this.value;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
helma.Http.Cookie.prototype.toString = function() {
|
||||
return "[helma.Http.Cookie " + this.name + " " + this.value + "]";
|
||||
};
|
||||
|
||||
helma.lib = "Http";
|
||||
helma.dontEnum(helma.lib);
|
||||
for (var i in helma[helma.lib])
|
||||
helma[helma.lib].dontEnum(i);
|
||||
for (var i in helma[helma.lib].prototype)
|
||||
helma[helma.lib].prototype.dontEnum(i);
|
||||
for (var i in helma[helma.lib].Cookie.prototype)
|
||||
helma[helma.lib].Cookie.prototype.dontEnum(i);
|
||||
delete helma.lib;
|
150
modules/helma/Image.js
Normal file
150
modules/helma/Image.js
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Image.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Methods of the helma.Image module.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/helma/Image.js')
|
||||
*/
|
||||
|
||||
if (!global.helma) {
|
||||
global.helma = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Image object, generated from the specified source.
|
||||
* <br /><br />
|
||||
* If the JIMI package is installed, an instance of
|
||||
* helma.image.jimi.JimiGenerator will be returned. Otherwise,
|
||||
* if the javax.imageio package is available, an instance of
|
||||
* helma.image.imageio.ImageIOGenerator is returned.
|
||||
* Additionally, the class of the ImageGenerator implementation
|
||||
* to be used can be set using the <code>imageGenerator</code>
|
||||
* property in either the app.properties or server.properties
|
||||
* file.
|
||||
*
|
||||
*
|
||||
* @param {helma.File|java.io.File|String} arg image source, filename or url
|
||||
* @return a new Image object
|
||||
* @singleton
|
||||
* @see Packages.helma.image.ImageGenerator
|
||||
* @see Packages.helma.image.jimi.JimiGenerator
|
||||
* @see Packages.helma.image.imageio.ImageIOGenerator
|
||||
*/
|
||||
helma.Image = function(arg) {
|
||||
// according to
|
||||
// http://grazia.helma.org/pipermail/helma-dev/2004-June/001253.html
|
||||
var generator = Packages.helma.image.ImageGenerator.getInstance();
|
||||
return generator.createImage(arg);
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
helma.Image.toString = function() {
|
||||
return "[helma.Image]";
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an ImageInfo object for the specified image file.
|
||||
*
|
||||
* @param {helma.File|java.io.File|String} arg image source, filename or url
|
||||
* @returns an ImageInfo object
|
||||
* @memberof helma.Image
|
||||
* @see Packages.helma.image.ImageInfo
|
||||
*/
|
||||
helma.Image.getInfo = function(arg) {
|
||||
if (arguments.length != 1) {
|
||||
throw new java.lang.IllegalArgumentException(
|
||||
"Image.getInfo() expects one argument"
|
||||
);
|
||||
}
|
||||
|
||||
var inp, result;
|
||||
var info = new Packages.helma.image.ImageInfo();
|
||||
// FIXME: we need a byte array for class comparison
|
||||
var b = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 0);
|
||||
|
||||
try {
|
||||
if (arg instanceof java.io.InputStream) {
|
||||
inp = new java.io.InputStream(arg);
|
||||
// FIXME: here comes a dirty hack to check for a byte array
|
||||
} else if (arg.getClass && arg.getClass() == b.getClass()) {
|
||||
inp = new java.io.ByteArrayInputStream(arg);
|
||||
} else if (arg instanceof java.io.File) {
|
||||
inp = new java.io.FileInputStream(arg);
|
||||
} else if (arg instanceof helma.File) {
|
||||
inp = new java.io.FileInputStream(arg.getFile());
|
||||
} else if (typeof arg == "string") {
|
||||
var str = arg;
|
||||
// try to interpret argument as URL if it contains a colon,
|
||||
// otherwise or if URL is malformed interpret as file name.
|
||||
if (str.indexOf(":") > -1) {
|
||||
try {
|
||||
var url = new java.net.URL(str);
|
||||
inp = url.openStream();
|
||||
} catch (mux) {
|
||||
inp = new java.io.FileInputStream(str);
|
||||
}
|
||||
} else {
|
||||
inp = new java.io.FileInputStream(str);
|
||||
}
|
||||
}
|
||||
if (inp == null) {
|
||||
var msg = "Unrecognized argument in Image.getInfo(): ";
|
||||
msg += (arg == null ? "null" : arg.getClass().toString());
|
||||
throw new java.lang.IllegalArgumentException(msg);
|
||||
}
|
||||
info.setInput(inp);
|
||||
if (info.check()) {
|
||||
result = info;
|
||||
}
|
||||
} catch (e) {
|
||||
// do nothing, returns null later
|
||||
} finally {
|
||||
if (inp != null) {
|
||||
try {
|
||||
inp.close();
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Writes a 1x1 pixel transparent spacer GIF image to the
|
||||
* response buffer and sets the content type to image/gif.
|
||||
*
|
||||
* @memberof helma.Image
|
||||
*/
|
||||
helma.Image.spacer = function() {
|
||||
res.contentType = "image/gif";
|
||||
res.writeBinary([71,73,70,56,57,97,2,0,2,0,-128,-1,0,-64,-64,-64,0,0,0,33,-7,4,1,0,0,0,0,44,0,0,0,0,1,0,1,0,64,2,2,68,1,0,59]);
|
||||
return;
|
||||
};
|
||||
|
||||
helma.lib = "Image";
|
||||
helma.dontEnum(helma.lib);
|
||||
for (var i in helma[helma.lib])
|
||||
helma[helma.lib].dontEnum(i);
|
||||
for (var i in helma[helma.lib].prototype)
|
||||
helma[helma.lib].prototype.dontEnum(i);
|
||||
delete helma.lib;
|
||||
|
||||
|
||||
|
705
modules/helma/Mail.js
Normal file
705
modules/helma/Mail.js
Normal file
|
@ -0,0 +1,705 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2007 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Mail.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the helma.Mail class.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/helma/Mail.js')
|
||||
*/
|
||||
|
||||
// take care of any dependencies
|
||||
app.addRepository('modules/helma/File.js');
|
||||
|
||||
/**
|
||||
* Define the global namespace if not existing
|
||||
*/
|
||||
if (!global.helma) {
|
||||
global.helma = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Mail client enabling you to send e-mail via SMTP using Packages.javax.mail.
|
||||
* <br /><br />
|
||||
* @class This class provides functionality to sending
|
||||
* Email messages.
|
||||
* A mail client object is created by using the helma.Mail()
|
||||
* constructor. The mail object then can be manipulated and sent
|
||||
* using the methods listed below.
|
||||
* <br /><br />
|
||||
* You will either need to set your mail server via the smtp
|
||||
* property in the app.properties or server.properties file
|
||||
* or pass the hostname of the mail server you want to use as a
|
||||
* parameter to the constructor.
|
||||
* <br /><br />
|
||||
* Note: Make sure that the SMTP server itself is well-configured,
|
||||
* so that it accepts e-mails coming from your server and does
|
||||
* not deny relaying. Best and fastest configuration is of course
|
||||
* if you run your own SMTP server (e.g. postfix) which might be
|
||||
* a bit tricky to set up, however.</p>
|
||||
*
|
||||
* @param {String} smtp as String, the hostname of the mail server
|
||||
* @constructor
|
||||
*/
|
||||
helma.Mail = function(host, port) {
|
||||
// Error code values for this.status
|
||||
var OK = 0;
|
||||
var SUBJECT = 10;
|
||||
var TEXT = 11;
|
||||
var MIMEPART = 12;
|
||||
var TO = 20;
|
||||
var CC = 21;
|
||||
var BCC = 22;
|
||||
var FROM = 23;
|
||||
var REPLYTO = 24;
|
||||
var SETHEADER = 25;
|
||||
var ADDHEADER = 26;
|
||||
var GETHEADER = 27;
|
||||
var REMOVEHEADER = 28;
|
||||
var SEND = 30;
|
||||
var MAILPKG = Packages.javax.mail;
|
||||
|
||||
var self = this;
|
||||
var errStr = "Error in helma.Mail";
|
||||
|
||||
var System = java.lang.System;
|
||||
var Properties = java.util.Properties;
|
||||
var IOException = java.io.IOException;
|
||||
var Wrapper = Packages.org.mozilla.javascript.Wrapper;
|
||||
var FileDataSource = Packages.javax.activation.FileDataSource;
|
||||
var DataHandler = Packages.javax.activation.DataHandler;
|
||||
|
||||
var MimePart = Packages.helma.util.MimePart;
|
||||
var MimePartDataSource = Packages.helma.util.MimePartDataSource;
|
||||
|
||||
var BodyPart = MAILPKG.BodyPart;
|
||||
var Message = MAILPKG.Message;
|
||||
var Session = MAILPKG.Session;
|
||||
var InternetAddress = MAILPKG.internet.InternetAddress;
|
||||
var AddressException = MAILPKG.internet.AddressException;
|
||||
var MimeBodyPart = MAILPKG.internet.MimeBodyPart;
|
||||
var MimeMessage = MAILPKG.internet.MimeMessage;
|
||||
var MimeUtility = MAILPKG.internet.MimeUtility;
|
||||
var MimeMultipart = MAILPKG.internet.MimeMultipart;
|
||||
|
||||
var buffer, multipart, multipartType = "mixed";
|
||||
var username, password;
|
||||
|
||||
var setStatus = function(status) {
|
||||
if (self.status === OK) {
|
||||
self.status = status;
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
var getStatus = function() {
|
||||
return self.status;
|
||||
};
|
||||
|
||||
var addRecipient = function(addstr, name, type) {
|
||||
if (addstr.indexOf("@") < 0) {
|
||||
throw new AddressException();
|
||||
}
|
||||
if (name != null) {
|
||||
var address = new InternetAddress(addstr,
|
||||
MimeUtility.encodeWord(name.toString()));
|
||||
} else {
|
||||
var address = new InternetAddress(addstr);
|
||||
}
|
||||
message.addRecipient(type, address);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds the content stored in this helma.Mail instance
|
||||
* to the wrapped message.
|
||||
* @private
|
||||
*/
|
||||
var setContent = function() {
|
||||
if (buffer != null) {
|
||||
if (multipart != null) {
|
||||
var part = new MimeBodyPart();
|
||||
part.setContent(buffer.toString(), "text/plain");
|
||||
multipart.addBodyPart(part, 0);
|
||||
message.setContent(multipart);
|
||||
} else {
|
||||
message.setText(buffer.toString());
|
||||
}
|
||||
} else if (multipart != null) {
|
||||
message.setContent(multipart);
|
||||
} else {
|
||||
message.setText("");
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the text buffer of this mail message
|
||||
* @returns The text buffer of this mail message
|
||||
* @type java.lang.StringBuffer
|
||||
* @private
|
||||
*/
|
||||
this.getBuffer = function() {
|
||||
return buffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the mime multipart object of this mail message
|
||||
* @returns The mime multipart object of this mail message
|
||||
* @type javax.mail.internet.MimeMultipart
|
||||
* @private
|
||||
*/
|
||||
this.getMultipart = function() {
|
||||
return multipart;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets username and password to use for SMTP authentication.
|
||||
* @param {String} uname The username to use
|
||||
* @param {String} pwd The password to use
|
||||
*/
|
||||
this.setAuthentication = function(uname, pwd) {
|
||||
if (uname && pwd) {
|
||||
username = uname;
|
||||
password = pwd;
|
||||
// enable smtp authentication
|
||||
props.put("mail.smtp.auth", "true");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapped message
|
||||
* @returns The wrapped message
|
||||
* @type javax.mail.internet.MimeMessage
|
||||
*/
|
||||
this.getMessage = function() {
|
||||
return message;
|
||||
};
|
||||
|
||||
/**
|
||||
* Switches debug mode on or off.
|
||||
* @param {Boolean} debug If true debug mode is enabled
|
||||
*/
|
||||
this.setDebug = function(debug) {
|
||||
session.setDebug(debug === true);
|
||||
};
|
||||
|
||||
/**
|
||||
* The status of this Mail object. This equals <code>0</code> unless
|
||||
* an error occurred. See {@link helma.Mail Mail.js} source code for a list of
|
||||
* possible error codes.
|
||||
*/
|
||||
this.status = OK;
|
||||
|
||||
/**
|
||||
* Sets the sender of an e-mail message.
|
||||
* <br /><br />
|
||||
* The first argument specifies the receipient's
|
||||
* e-mail address. The optional second argument
|
||||
* specifies the name of the recipient.
|
||||
*
|
||||
* @param {String} addstr as String, sender email address
|
||||
* @param {String} name as String, optional sender name
|
||||
*/
|
||||
this.setFrom = function(addstr, name) {
|
||||
try {
|
||||
if (addstr.indexOf("@") < 0) {
|
||||
throw new AddressException();
|
||||
}
|
||||
if (name != null) {
|
||||
var address = new InternetAddress(addstr,
|
||||
MimeUtility.encodeWord(name.toString()));
|
||||
} else {
|
||||
var address = new InternetAddress(addstr);
|
||||
}
|
||||
message.setFrom(address);
|
||||
} catch (mx) {
|
||||
app.logger.error(errStr + ".setFrom(): " + mx);
|
||||
setStatus(FROM);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a header in the e-mail message. If the given header is already set the previous
|
||||
* value is replaced with the new one.
|
||||
* @param name a header name
|
||||
* @param value the header value
|
||||
*/
|
||||
this.setHeader = function(name, value) {
|
||||
try {
|
||||
message.addHeader(name, MimeUtility.encodeText(value));
|
||||
} catch (mx) {
|
||||
app.logger.error(errStr + ".setHeader(): " + mx);
|
||||
setStatus(SETHEADER);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a header in the e-mail message. If the given header is already set the previous
|
||||
* value is replaced with the new one.
|
||||
* @param name a header name
|
||||
* @param value the header value
|
||||
*/
|
||||
this.addHeader = function(name, value) {
|
||||
try {
|
||||
message.addHeader(name, MimeUtility.encodeText(value));
|
||||
} catch (mx) {
|
||||
app.logger.error(errStr + ".addHeader(): " + mx);
|
||||
setStatus(ADDHEADER);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the headers for this header name.
|
||||
* Returns null if no headers for this header name are available.
|
||||
* @param name a header name
|
||||
* @return {String[]} a string array of header values, or null
|
||||
*/
|
||||
this.getHeader = function(name) {
|
||||
var value = null;
|
||||
try {
|
||||
value = message.getHeader(name);
|
||||
if (value && value.length) {
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
value[i] = MimeUtility.decodeText(value[i]);
|
||||
}
|
||||
}
|
||||
} catch (mx) {
|
||||
app.logger.error(errStr + ".getHeader(): " + mx);
|
||||
setStatus(GETHEADER);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all headers with this name.
|
||||
* @param name the header name
|
||||
*/
|
||||
this.removeHeader = function(name) {
|
||||
try {
|
||||
message.removeHeader(name);
|
||||
} catch (mx) {
|
||||
app.logger.error(errStr + ".removeHeader(): " + mx);
|
||||
setStatus(REMOVEHEADER);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Reply-To address of an e-mail message.
|
||||
*
|
||||
* @param {String} addstr as String, the reply-to email address
|
||||
*/
|
||||
this.setReplyTo = function(addstr) {
|
||||
try {
|
||||
if (addstr.indexOf("@") < 0) {
|
||||
throw new AddressException();
|
||||
}
|
||||
var address = [new InternetAddress(addstr)];
|
||||
message.setReplyTo(address);
|
||||
} catch (mx) {
|
||||
app.logger.error(errStr + ".setReplyTo(): " + mx);
|
||||
setStatus(REPLYTO);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the recipient of an e-mail message.
|
||||
*
|
||||
* The first argument specifies the receipient's
|
||||
* e-mail address. The optional second argument
|
||||
* specifies the name of the recipient.
|
||||
*
|
||||
* @param {String} addstr as String, receipients email address
|
||||
* @param {String} name as String, optional receipients name
|
||||
* @see #addTo
|
||||
*/
|
||||
this.setTo = function(addstr, name) {
|
||||
try {
|
||||
addRecipient(addstr, name, Message.RecipientType.TO);
|
||||
} catch (mx) {
|
||||
app.logger.error(errStr + ".setTo(): " + mx);
|
||||
setStatus(TO);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a recipient to the address list of an e-mail message.
|
||||
* <br /><br />
|
||||
* The first argument specifies the receipient's
|
||||
* e-mail address. The optional second argument
|
||||
* specifies the name of the recipient.
|
||||
*
|
||||
* @param {String} addstr as String, receipients email address
|
||||
* @param {String} name as String, optional receipients name
|
||||
* @see setTo
|
||||
*/
|
||||
this.addTo = function(addstr, name) {
|
||||
try {
|
||||
addRecipient(addstr, name, Message.RecipientType.TO);
|
||||
} catch (mx) {
|
||||
app.logger.error(errStr + ".addTo(): " + mx);
|
||||
setStatus(TO);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a recipient to the list of addresses to get a "carbon copy"
|
||||
* of an e-mail message.
|
||||
* <br /><br />
|
||||
* The first argument specifies the receipient's
|
||||
* e-mail address. The optional second argument
|
||||
* specifies the name of the recipient.
|
||||
*
|
||||
* @param {String} addstr as String, receipients email address
|
||||
* @param {String} name as String, optional receipients name
|
||||
*/
|
||||
this.addCC = function(addstr, name) {
|
||||
try {
|
||||
addRecipient(addstr, name, Message.RecipientType.CC);
|
||||
} catch (mx) {
|
||||
app.logger.error(errStr + ".addCC(): " + mx);
|
||||
setStatus(CC);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a recipient to the list of addresses to get a "blind carbon copy" of an e-mail message.
|
||||
* <br /><br />
|
||||
* The first argument specifies the receipient's
|
||||
* e-mail address. The optional second argument
|
||||
* specifies the name of the recipient.
|
||||
*
|
||||
* @param {String} addstr as String, receipients email address
|
||||
* @param {String} name as String, optional receipients name
|
||||
*/
|
||||
this.addBCC = function(addstr, name) {
|
||||
try {
|
||||
addRecipient(addstr, name, Message.RecipientType.BCC);
|
||||
} catch (mx) {
|
||||
app.logger.error(errStr + ".addBCC(): " + mx);
|
||||
setStatus(BCC);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the subject of an e-mail message.
|
||||
*
|
||||
* @param {String} subject as String, the email subject
|
||||
*/
|
||||
this.setSubject = function(subject) {
|
||||
if (!subject) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
message.setSubject(MimeUtility.encodeWord(subject.toString()));
|
||||
} catch (mx) {
|
||||
app.logger.error(errStr + ".setSubject(): " + mx);
|
||||
setStatus(SUBJECT);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the body text of an e-mail message.
|
||||
*
|
||||
* @param {String} text as String, to be appended to the message body
|
||||
* @see #addText
|
||||
*/
|
||||
this.setText = function(text) {
|
||||
if (text) {
|
||||
buffer = new java.lang.StringBuffer(text);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Appends a string to the body text of an e-mail message.
|
||||
*
|
||||
* @param {String} text as String, to be appended to the message body
|
||||
* @see #setText
|
||||
*/
|
||||
this.addText = function(text) {
|
||||
if (buffer == null) {
|
||||
buffer = new java.lang.StringBuffer(text);
|
||||
} else {
|
||||
buffer.append(text);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the MIME multiparte message subtype. The default value is
|
||||
* "mixed" for messages of type multipart/mixed. A common value
|
||||
* is "alternative" for the multipart/alternative MIME type.
|
||||
* @param {String} messageType the MIME subtype such as "mixed" or "alternative".
|
||||
* @see #getMultipartType
|
||||
* @see #addPart
|
||||
*/
|
||||
this.setMultipartType = function(messageType) {
|
||||
multipartType = messageType;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the MIME multiparte message subtype. The default value is
|
||||
* "mixed" for messages of type multipart/mixed.
|
||||
* @return the MIME subtype
|
||||
* @type String
|
||||
* @see #setMultipartType
|
||||
* @see #addPart
|
||||
*/
|
||||
this.getMultipartType = function(messageType) {
|
||||
return multipartType;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds an attachment to an e-mail message.
|
||||
* <br /><br />
|
||||
* The attachment needs to be either a helma.util.MimePart Object retrieved
|
||||
* through the global getURL function, or a {@link helma.File} object, or a String.
|
||||
* <br /><br />
|
||||
* Use the getURL() function to retrieve a MIME object or wrap a
|
||||
* helma.File object around a file of the local file system.
|
||||
*
|
||||
* @param {fileOrMimeObjectOrString} obj File, Mime object or String to attach to the email
|
||||
* @param {String} filename optional name of the attachment
|
||||
* @param {String} contentType optional content type (only if first argument is a string)
|
||||
* @see global.getURL
|
||||
* @see helma.util.MimePart
|
||||
* @see helma.File
|
||||
*/
|
||||
this.addPart = function(obj, filename, contentType) {
|
||||
try {
|
||||
if (obj == null) {
|
||||
throw new IOException(
|
||||
errStr + ".addPart: method called with wrong number of arguments."
|
||||
);
|
||||
}
|
||||
if (multipart == null) {
|
||||
multipart = new MimeMultipart(multipartType);
|
||||
}
|
||||
if (obj instanceof Wrapper) {
|
||||
obj = obj.unwrap();
|
||||
}
|
||||
|
||||
var part;
|
||||
if (obj instanceof BodyPart) {
|
||||
// we already got a body part, no need to convert it
|
||||
part = obj;
|
||||
} else {
|
||||
part = new MimeBodyPart();
|
||||
if (typeof obj == "string") {
|
||||
part.setContent(obj.toString(), contentType || "text/plain");
|
||||
} else if (obj instanceof File || obj instanceof helma.File) {
|
||||
var source = new FileDataSource(obj.getPath());
|
||||
part.setDataHandler(new DataHandler(source));
|
||||
} else if (obj instanceof MimePart) {
|
||||
var source = new MimePartDataSource(obj);
|
||||
part.setDataHandler(new DataHandler(source));
|
||||
}
|
||||
}
|
||||
if (filename != null) {
|
||||
try {
|
||||
part.setFileName(filename.toString());
|
||||
} catch (x) {}
|
||||
} else if (obj instanceof File || obj instanceof helma.File) {
|
||||
try {
|
||||
part.setFileName(obj.getName());
|
||||
} catch (x) {}
|
||||
}
|
||||
multipart.addBodyPart(part);
|
||||
} catch (mx) {
|
||||
app.logger.error(errStr + ".addPart(): " + mx);
|
||||
setStatus(MIMEPART);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Saves this mail RFC 822 formatted into a file. The name of the
|
||||
* file is prefixed with "helma.Mail" followed by the current time
|
||||
* in milliseconds and a random number.
|
||||
* @param {helma.File} dir An optional directory where to save
|
||||
* this mail to. If omitted the mail will be saved in the system's
|
||||
* temp directory.
|
||||
*/
|
||||
this.writeToFile = function(dir) {
|
||||
if (!dir || !dir.exists() || !dir.canWrite()) {
|
||||
dir = new java.io.File(System.getProperty("java.io.tmpdir"));
|
||||
}
|
||||
var fileName = "helma.Mail." + (new Date()).getTime() +
|
||||
"." + Math.round(Math.random() * 1000000);
|
||||
var file = new java.io.File(dir, fileName);
|
||||
if (file.exists()) {
|
||||
file["delete"]();
|
||||
}
|
||||
try {
|
||||
setContent();
|
||||
var fos = new java.io.FileOutputStream(file);
|
||||
var os = new java.io.BufferedOutputStream(fos);
|
||||
message.writeTo(os);
|
||||
os.close();
|
||||
app.logger.info("helma.Mail.saveTo(): saved mail to " +
|
||||
file.getAbsolutePath());
|
||||
} catch (e) {
|
||||
app.logger.error(errStr + ".saveTo(): " + e);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the source of this mail as RFC 822 formatted string.
|
||||
* @returns The source of this mail as RFC 822 formatted string
|
||||
* @type String
|
||||
*/
|
||||
this.getSource = function() {
|
||||
try {
|
||||
setContent();
|
||||
var buf = new java.io.ByteArrayOutputStream();
|
||||
var os = new java.io.BufferedOutputStream(buf);
|
||||
message.writeTo(os);
|
||||
os.close();
|
||||
return buf.toString();
|
||||
} catch (e) {
|
||||
app.logger.error(errStr + ".getSource(): " + e);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends an e-mail message.
|
||||
* <br /><br />
|
||||
* This function sends the message using the SMTP
|
||||
* server as specified when the Mail object was
|
||||
* constructed using helma.Mail.
|
||||
* <br /><br />
|
||||
* If no smtp hostname was specified when the Mail
|
||||
* object was constructed, the smtp property in either
|
||||
* the app.properties or server.properties file needs
|
||||
* to be set in order for this to work.
|
||||
* <br /><br />
|
||||
* As a fallback, the message will then be written to
|
||||
* file using the {@link #writeToFile} method.
|
||||
* Additionally, the location of the message files can
|
||||
* be determined by setting smtp.dir in app.properties
|
||||
* to the desired file path.
|
||||
*/
|
||||
this.send = function() {
|
||||
if (this.status > OK) {
|
||||
app.logger.error(errStr + ".send(): Status is " + this.status);
|
||||
return;
|
||||
}
|
||||
if (host != null) {
|
||||
try {
|
||||
setContent();
|
||||
message.setSentDate(new Date());
|
||||
var transport = session.getTransport("smtp");
|
||||
if (username && password) {
|
||||
transport.connect(host, username, password);
|
||||
} else {
|
||||
transport.connect();
|
||||
}
|
||||
message.saveChanges();
|
||||
transport.sendMessage(message, message.getAllRecipients());
|
||||
} catch (mx) {
|
||||
app.logger.error(errStr + ".send(): " + mx);
|
||||
setStatus(SEND);
|
||||
} finally {
|
||||
if (transport != null && transport.isConnected()) {
|
||||
transport.close();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no smtp host is given, so write the mail to a file
|
||||
this.writeToFile(getProperty("smtp.dir"));
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Main constructor body
|
||||
*/
|
||||
var props = new Properties();
|
||||
if (host || (host = getProperty("smtp"))) {
|
||||
props.put("mail.transport.protocol", "smtp");
|
||||
props.put("mail.smtp.host", String(host));
|
||||
props.put("mail.smtp.port", String(port || 25));
|
||||
props.put("mail.smtp.starttls.enable",
|
||||
getProperty("smtp.tls") || "false");
|
||||
props.put("mail.mime.charset",
|
||||
getProperty("smtp.charset") ||
|
||||
System.getProperty("mail.charset") ||
|
||||
"ISO-8859-15");
|
||||
}
|
||||
|
||||
this.setAuthentication(getProperty("smtp.username"),
|
||||
getProperty("smtp.password"));
|
||||
var session = Session.getInstance(props);
|
||||
var message = new MimeMessage(session);
|
||||
|
||||
for (var i in this)
|
||||
this.dontEnum(i);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/** @ignore */
|
||||
helma.Mail.toString = function() {
|
||||
return "[helma.Mail]";
|
||||
};
|
||||
|
||||
|
||||
/** @ignore */
|
||||
helma.Mail.prototype.toString = function() {
|
||||
return "[helma.Mail Object]";
|
||||
};
|
||||
|
||||
helma.Mail.example = function(host, sender, addr, subject, text) {
|
||||
// var smtp = "smtp.host.dom";
|
||||
// var sender = "sender@host.dom";
|
||||
// var addr = "recipient@host.dom";
|
||||
// var subject = "Hello, World!";
|
||||
// var text = "This is a test.";
|
||||
var port = 25;
|
||||
var msg = new helma.Mail(host, port);
|
||||
msg.setFrom(sender);
|
||||
msg.addTo(addr);
|
||||
msg.setSubject(subject);
|
||||
msg.setText(text);
|
||||
msg.send();
|
||||
res.write(msg.status);
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
helma.lib = "Mail";
|
||||
helma.dontEnum(helma.lib);
|
||||
for (var i in helma[helma.lib])
|
||||
helma[helma.lib].dontEnum(i);
|
||||
for (var i in helma[helma.lib].prototype)
|
||||
helma[helma.lib].prototype.dontEnum(i);
|
||||
delete helma.lib;
|
1458
modules/helma/Search.js
Normal file
1458
modules/helma/Search.js
Normal file
File diff suppressed because it is too large
Load diff
124
modules/helma/Skin.js
Normal file
124
modules/helma/Skin.js
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Skin.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the helma.Skin class.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/helma/Skin.js')
|
||||
*/
|
||||
|
||||
|
||||
// define the helma namespace, if not existing
|
||||
if (!global.helma) {
|
||||
global.helma = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of helma.Skin
|
||||
* @class Instances of this class represent a Helma skin. In addition
|
||||
* to the standard skin functionality this class allows creation of
|
||||
* a skin based on a Base64 encoded source.
|
||||
* @param {String} source The source of the skin
|
||||
* @param {Boolean} encFlag If true the source will be Base64-decoded.
|
||||
* @constructor
|
||||
* @returns A newly created instance of helma.Skin
|
||||
*/
|
||||
helma.Skin = function(source, encFlag) {
|
||||
/** @ignore */
|
||||
var Base64 = Packages.helma.util.Base64;
|
||||
|
||||
if (!encFlag) {
|
||||
var skin = createSkin(source);
|
||||
} else {
|
||||
var encoded = source;
|
||||
source = new java.lang.String(source);
|
||||
var bytes = Base64.decode(source.toCharArray());
|
||||
var skin = createSkin(new java.lang.String(bytes, "UTF-8"));
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
this.toString = function() {
|
||||
return source;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the source of the skin as Base64 encoded string
|
||||
* @returns The source of the skin as Base64 encoded string
|
||||
* @type String
|
||||
*/
|
||||
this.valueOf = function() {
|
||||
if (encFlag) {
|
||||
return encoded;
|
||||
}
|
||||
var bytes = new java.lang.String(source).getBytes("UTF-8");
|
||||
return new java.lang.String(Base64.encode(bytes));
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the skin.
|
||||
* @param {Object} param An optional parameter object to pass to the skin.
|
||||
*/
|
||||
this.render = function(param) {
|
||||
return renderSkin(skin, param);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the rendered skin.
|
||||
* @param {Object} param An optional parameter object to pass to the skin.
|
||||
* @type String
|
||||
*/
|
||||
this.renderAsString = function(param) {
|
||||
return renderSkinAsString(skin, param);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the skin contains a macro with the name
|
||||
* and optional handler passed as argument.
|
||||
* @param {String} name The name of the macro
|
||||
* @param {String} handler An optional macro handler name
|
||||
* @returns True if the skin contains this macro at least once,
|
||||
* false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
this.containsMacro = function(name, handler) {
|
||||
res.push();
|
||||
res.write("<% *");
|
||||
if (handler) {
|
||||
res.write(handler);
|
||||
res.write(".");
|
||||
}
|
||||
res.write(name);
|
||||
res.write(" *%>");
|
||||
var re = new RegExp(res.pop(), "g");
|
||||
return re.test(source);
|
||||
};
|
||||
|
||||
for (var i in this)
|
||||
this.dontEnum(i);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
helma.lib = "Skin";
|
||||
helma.dontEnum(helma.lib);
|
||||
for (var i in helma[helma.lib])
|
||||
helma[helma.lib].dontEnum(i);
|
||||
for (var i in helma[helma.lib].prototype)
|
||||
helma[helma.lib].prototype.dontEnum(i);
|
||||
delete helma.lib;
|
375
modules/helma/Ssh.js
Normal file
375
modules/helma/Ssh.js
Normal file
|
@ -0,0 +1,375 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Ssh.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the helma.Ssh class.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/helma/Ssh.js')
|
||||
*/
|
||||
|
||||
// take care of any dependencies
|
||||
app.addRepository('modules/helma/File.js');
|
||||
app.addRepository('modules/helma/ganymed-ssh2.jar');
|
||||
|
||||
// define the helma namespace, if not existing
|
||||
if (!global.helma) {
|
||||
global.helma = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of helma.Ssh
|
||||
* @class This class provides methods for connecting to a remote
|
||||
* server via secure shell (ssh) and copying files from/to a remote
|
||||
* server using secure copy (scp). It utilizes "Ganymed SSH-2 for Java"
|
||||
* (see <a href="http://www.ganymed.ethz.ch/ssh2/">http://www.ganymed.ethz.ch/ssh2/</a>).
|
||||
* @param {String} server The server to connect to
|
||||
* @param {helma.File|java.io.File|String} hosts Either a file
|
||||
* containing a list of known hosts, or the path pointing to a
|
||||
* file. This argument is optional.
|
||||
* @constructor
|
||||
* @returns A newly created instance of helma.Ssh
|
||||
* @author Robert Gaggl <robert@nomatic.org>
|
||||
*/
|
||||
helma.Ssh = function(server, hosts) {
|
||||
var SSHPKG = Packages.ch.ethz.ssh2;
|
||||
var SSHPKGNAME = "ganymed-ssh2.jar";
|
||||
var SSHPKGURL = "http://www.ganymed.ethz.ch/ssh2";
|
||||
var className = "helma.Ssh";
|
||||
var paranoid = false;
|
||||
var verifier = null;
|
||||
var knownHosts, connection;
|
||||
|
||||
// check if necessary jar file is in classpath
|
||||
try {
|
||||
knownHosts = new SSHPKG.KnownHosts();
|
||||
connection = new SSHPKG.Connection(server);
|
||||
} catch (e) {
|
||||
if (e instanceof TypeError == false)
|
||||
throw(e);
|
||||
throw("helma.Ssh needs " + SSHPKGNAME +
|
||||
" in lib/ext or application directory " +
|
||||
"[" + SSHPKGURL + "]");
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple verifier for verifying host keys
|
||||
* @private
|
||||
*/
|
||||
var SimpleVerifier = {
|
||||
verifyServerHostKey: function(hostname, port, serverHostKeyAlgorithm, serverHostKey) {
|
||||
var result = knownHosts.verifyHostkey(hostname, serverHostKeyAlgorithm, serverHostKey);
|
||||
switch (result) {
|
||||
case SSHPKG.KnownHosts.HOSTKEY_IS_OK:
|
||||
debug("verifyServerHostKey", "received known host key, proceeding");
|
||||
return true;
|
||||
case SSHPKG.KnownHosts.HOSTKEY_IS_NEW:
|
||||
if (paranoid == true) {
|
||||
debug("verifyServerHostKey", "received unknown host key, rejecting");
|
||||
return false;
|
||||
} else {
|
||||
debug("verifyServerHostKey", "received new host key, adding temporarily to known hosts");
|
||||
var hn = java.lang.reflect.Array.newInstance(java.lang.String, 1);
|
||||
hn[0] = hostname;
|
||||
knownHosts.addHostkey(hn, serverHostKeyAlgorithm, serverHostKey);
|
||||
return true;
|
||||
}
|
||||
case SSHPKG.KnownHosts.HOSTKEY_HAS_CHANGED:
|
||||
debug("verifyServerHostKey", "WARNING: host key has changed, rejecting");
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts the argument into an instance of java.io.File
|
||||
* @param {helma.File|java.io.File|String} file Either a file
|
||||
* object or the path to a file as string
|
||||
* @returns The argument converted into a file object
|
||||
* @type java.io.File
|
||||
* @private
|
||||
*/
|
||||
var getFile = function(file) {
|
||||
if (file instanceof helma.File) {
|
||||
return new java.io.File(file.getAbsolutePath());
|
||||
} else if (file instanceof java.io.File) {
|
||||
return file;
|
||||
} else if (file.constructor == String) {
|
||||
return new java.io.File(file);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Connects to the remote server
|
||||
* @return Boolean
|
||||
* @private
|
||||
*/
|
||||
var connect = function() {
|
||||
try {
|
||||
var info = connection.connect(verifier);
|
||||
debug("connect", "connected to server " + server);
|
||||
return true;
|
||||
} catch (e) {
|
||||
error("connect", "connection to " + server + " failed.");
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Private helper method for debugging output using app.logger
|
||||
* @param {String} methodName The name of the method
|
||||
* @param {String} msg The debug message to write to event log file
|
||||
* @private
|
||||
*/
|
||||
var debug = function(methodName, msg) {
|
||||
var msg = msg ? " " + msg : "";
|
||||
app.logger.debug(className + ":" + methodName + msg);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Private helper method for error output using app.logger
|
||||
* @param {String} methodName The name of the method
|
||||
* @param {String} msg The error message to write to event log file
|
||||
* @private
|
||||
*/
|
||||
var error = function(methodName, msg) {
|
||||
var tx = java.lang.Thread.currentThread();
|
||||
tx.dumpStack();
|
||||
app.logger.error(className + ":" + methodName + ": " + msg);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens the file passed as argument and adds the known hosts
|
||||
* therein to the list of known hosts for this client.
|
||||
* @param {helma.File|java.io.File|String} file Either a file object
|
||||
* or the path to a file containing a list of known hosts
|
||||
* @returns True if adding the list was successful, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
this.addKnownHosts = function(file) {
|
||||
try {
|
||||
knownHosts.addHostkeys(getFile(file));
|
||||
verifier = new SSHPKG.ServerHostKeyVerifier(SimpleVerifier);
|
||||
return true;
|
||||
} catch (e) {
|
||||
error("addKnownHosts", "Missing or invalid known hosts file '" + file + "'");
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Connects to a remote host using plain username/password authentication.
|
||||
* @param {String} username The username
|
||||
* @param {String} password The password
|
||||
* @returns True in case the connection attempt was successful, false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
this.connect = function(username, password) {
|
||||
if (!username || !password) {
|
||||
error("connect", "Insufficient arguments.");
|
||||
} else if (connect() && connection.authenticateWithPassword(username, password)) {
|
||||
debug("connect", "authenticated using password");
|
||||
return true;
|
||||
} else {
|
||||
error("connect", "Authentication failed!");
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Connects to a remote host using a private key and the corresponding
|
||||
* passphrase.
|
||||
* @param {String} username The username
|
||||
* @param {helma.File|java.io.File|String} key Either a file object
|
||||
* representing the private key file, or the path to it.
|
||||
* @param {String} passphrase The passphrase of the private key, if necessary.
|
||||
* @returns True in case the connection attempt was successful, false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
this.connectWithKey = function(username, key, passphrase) {
|
||||
var keyFile;
|
||||
if (!username || !(keyFile = getFile(key))) {
|
||||
error("connectWithKey", "Insufficient or wrong arguments.");
|
||||
} else if (connect() && connection.authenticateWithPublicKey(username, keyFile, passphrase)) {
|
||||
debug("connectWithKey", "authenticated with key");
|
||||
return true;
|
||||
} else {
|
||||
error("connectWithKey", "Authentication failed!");
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Disconnects this client from the remote server.
|
||||
*/
|
||||
this.disconnect = function() {
|
||||
connection.close();
|
||||
debug("disconnect", "disconnected from server " + server);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if this client is currently connected.
|
||||
* @returns True in case this client is connected, false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
this.isConnected = function() {
|
||||
return (connection != null && connection.isAuthenticationComplete());
|
||||
};
|
||||
|
||||
/**
|
||||
* Copies a local file to the remote server
|
||||
* @param {String|Array} localFile Either the path to a single local
|
||||
* file or an array containing multiple file paths that should be
|
||||
* copied to the remote server.
|
||||
* @param {String} remoteDir The path to the remote destination directory
|
||||
* @param {String} mode An optional 4-digit permission mode string (eg.
|
||||
* <code>0755</code>);
|
||||
* @returns True in case the operation was successful, false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
this.put = function(localFile, remoteDir, mode) {
|
||||
if (!localFile || !remoteDir) {
|
||||
error("put", "Insufficient arguments.");
|
||||
} else if (!this.isConnected()) {
|
||||
error("put", "Not connected. Please establish a connection first.");
|
||||
} else {
|
||||
try {
|
||||
var scp = connection.createSCPClient();
|
||||
if (mode != null)
|
||||
scp.put(localFile, remoteDir, mode);
|
||||
else
|
||||
scp.put(localFile, remoteDir);
|
||||
debug("put", "copied '" + localFile + "' to '" + remoteDir + "'");
|
||||
return true;
|
||||
} catch (e) {
|
||||
error("put", e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves a file from the remote server and stores it locally.
|
||||
* @param {String|Array} remoteFile Either the path to a single remote
|
||||
* file or an array containing multiple file paths that should be
|
||||
* copied onto the local disk.
|
||||
* @param {String} targetDir The path to the local destination directory
|
||||
* @returns True if the copy process was successful, false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
this.get = function(remoteFile, targetDir) {
|
||||
if (!remoteFile || !targetDir) {
|
||||
error("get", "Insufficient arguments.");
|
||||
} else if (!this.isConnected()) {
|
||||
error("get", "Not connected. Please establish a connection first.");
|
||||
} else {
|
||||
try {
|
||||
var scp = connection.createSCPClient();
|
||||
scp.get(remoteFile, targetDir);
|
||||
debug("get", "copied '" + remoteFile + "' to '" + targetDir + "'");
|
||||
return true;
|
||||
} catch (e) {
|
||||
error("get", e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Executes a single command on the remote server.
|
||||
* @param {String} cmd The command to execute on the remote server.
|
||||
* @return The result of the command execution
|
||||
* @type String
|
||||
*/
|
||||
this.execCommand = function(cmd) {
|
||||
if (!this.isConnected()) {
|
||||
error("execCommand", "Not connected. Please establish a connection first.");
|
||||
} else {
|
||||
var session = connection.openSession();
|
||||
try {
|
||||
session.execCommand(cmd);
|
||||
var stdout = new SSHPKG.StreamGobbler(session.getStdout());
|
||||
var br = new java.io.BufferedReader(new java.io.InputStreamReader(stdout));
|
||||
res.push();
|
||||
while (true) {
|
||||
if (!(line = br.readLine()))
|
||||
break;
|
||||
res.writeln(line);
|
||||
}
|
||||
debug("execCommand", "executed command '" + cmd + "'");
|
||||
return res.pop();
|
||||
} catch (e) {
|
||||
error("execCommand", e);
|
||||
} finally {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggles paranoid mode. If set to true this client tries to
|
||||
* verify the host key against the its list of known hosts
|
||||
* during connection and rejects if the host key is not found
|
||||
* therein or is different.
|
||||
* @param {Boolean} p Either true or false
|
||||
*/
|
||||
this.setParanoid = function(p) {
|
||||
paranoid = (p === true);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if this client is in paranoid mode.
|
||||
* @return Boolean
|
||||
* @see #setParanoid
|
||||
*/
|
||||
this.isParanoid = function() {
|
||||
return paranoid;
|
||||
};
|
||||
|
||||
/**
|
||||
* main constructor body
|
||||
*/
|
||||
if (hosts) {
|
||||
this.addKnownHosts(hosts);
|
||||
}
|
||||
|
||||
for (var i in this)
|
||||
this.dontEnum(i);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/** @ignore */
|
||||
helma.Ssh.toString = function() {
|
||||
return "[helma.Ssh]";
|
||||
};
|
||||
|
||||
|
||||
helma.lib = "Ssh";
|
||||
helma.dontEnum(helma.lib);
|
||||
for (var i in helma[helma.lib])
|
||||
helma[helma.lib].dontEnum(i);
|
||||
for (var i in helma[helma.lib].prototype)
|
||||
helma[helma.lib].prototype.dontEnum(i);
|
||||
delete helma.lib;
|
126
modules/helma/Url.js
Normal file
126
modules/helma/Url.js
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2007 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Url.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the helma.Url class.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/helma/Url.js')
|
||||
*/
|
||||
|
||||
if (!global.helma) {
|
||||
global.helma = {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a helma.Url object from a provided url string.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
helma.Url = function(str) {
|
||||
if (!str || !helma.Url.PATTERN.test(str))
|
||||
throw Error("Cannot create helma.Url: insufficient arguments");
|
||||
|
||||
// filter punctuation from user-generated urls
|
||||
// FIXME: a) can this be done in helma.Url.PATTERN?
|
||||
// b) should it be done rather in methods like activateUrls?
|
||||
str = str.replace(/[,.;:]\s/, "");
|
||||
|
||||
var parts = helma.Url.PATTERN.exec(str);
|
||||
/**
|
||||
* Protocol segment of this URL
|
||||
*/
|
||||
this.protocol = parts[1];
|
||||
|
||||
if (!parts[2]) {
|
||||
if (parts[3])
|
||||
/**
|
||||
* User name segment of this URL
|
||||
*/
|
||||
this.user = parts[3];
|
||||
} else {
|
||||
this.user = parts[2];
|
||||
if (parts[3])
|
||||
/**
|
||||
* Password segment of this URL
|
||||
*/
|
||||
this.password = parts[3];
|
||||
}
|
||||
|
||||
if (!parts[4])
|
||||
throw Error("Cannot create helma.Url: missing host part");
|
||||
|
||||
/**
|
||||
* Fully qualified domain name segment of this URL
|
||||
*/
|
||||
this.domainName = parts[4]; // actually, the fully-qualified domain name
|
||||
var fqdnParts = this.domainName.split(".");
|
||||
if (fqdnParts.length < 3)
|
||||
this.host = "";
|
||||
else {
|
||||
/**
|
||||
* Host name segment of this URL
|
||||
*/
|
||||
this.host = fqdnParts[0];
|
||||
fqdnParts.splice(0, 1);
|
||||
}
|
||||
/**
|
||||
* Top level domain name segment of this URL
|
||||
*/
|
||||
this.topLevelDomain = fqdnParts[fqdnParts.length-1];
|
||||
/**
|
||||
* Domain name segment of this URL
|
||||
*/
|
||||
this.domain = fqdnParts.join(".");
|
||||
|
||||
/**
|
||||
* Request path segment of this URL as string
|
||||
*/
|
||||
this.pathString = parts[5] || "";
|
||||
if (this.pathString.indexOf("/") == 0)
|
||||
this.pathString = this.pathString.substring(1);
|
||||
/**
|
||||
* Request path segment of this URL as array
|
||||
*/
|
||||
this.path = this.pathString.split("/");
|
||||
/**
|
||||
* File name segment of this URL
|
||||
*/
|
||||
this.file = this.path.pop();
|
||||
|
||||
if (parts[6]) {
|
||||
/**
|
||||
* Query parameter segment of this URL as string
|
||||
*/
|
||||
this.queryString = parts[6];
|
||||
var pairs;
|
||||
/**
|
||||
* Query parameter segment of this URL as object
|
||||
*/
|
||||
this.query = {};
|
||||
parts = parts[6].split("&");
|
||||
for (var i in parts) {
|
||||
pairs = parts[i].split("=");
|
||||
this.query[pairs[0]] = pairs[1];
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
helma.Url.PATTERN = /^([^:]*):\/\/+(?:([^\/]*):)?(?:([^\/]*)@)?([\w\-_.]*[^.])(\/[^?]*)?(?:\?(.*))?$/;
|
503
modules/helma/Zip.js
Normal file
503
modules/helma/Zip.js
Normal file
|
@ -0,0 +1,503 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Zip.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the helma.Zip class.
|
||||
* <br /><br />
|
||||
* To use this optional module, its repository needs to be added to the
|
||||
* application, for example by calling app.addRepository('modules/helma/Zip.js')
|
||||
*/
|
||||
|
||||
// take care of any dependencies
|
||||
app.addRepository('modules/helma/File.js');
|
||||
|
||||
// define the helma namespace, if not existing
|
||||
if (!global.helma) {
|
||||
global.helma = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new helma.Zip instance
|
||||
* @class Instances of this class represent a single zip archive
|
||||
* and provide various methods for extracting entries or manipulating
|
||||
* the contents of the archive.
|
||||
* @param {helma.File|java.io.File|String} file Either
|
||||
* a file object representing the .zip file on disk, or the
|
||||
* path to the .zip file as string.
|
||||
* @constructor
|
||||
* @returns A newly created instance of helma.Zip.
|
||||
* @author Robert Gaggl <robert@nomatic.org>
|
||||
*/
|
||||
helma.Zip = function(file) {
|
||||
|
||||
/**
|
||||
* Private method that extracts the data of a single file
|
||||
* in a .zip archive. If a destination path is given it
|
||||
* writes the extracted data directly to disk using the
|
||||
* name of the ZipEntry Object, otherwise it returns the
|
||||
* byte array containing the extracted data.
|
||||
* @param {java.util.zip.ZipFile} zFile The zip archive to extract
|
||||
* the file from.
|
||||
* @param {java.util.zip.ZipEntry} entry The zip entry to extract
|
||||
* @param {String} destPath The destination path where the extracted
|
||||
* file should be stored.
|
||||
* @returns If no destination path is given, this method returns
|
||||
* the contents of the extracted file as ByteArray, otherwise
|
||||
* it returns null.
|
||||
* @private
|
||||
*/
|
||||
var extractEntry = function(zFile, entry, destPath) {
|
||||
var size = entry.getSize();
|
||||
if (entry.isDirectory() || size <= 0)
|
||||
return null;
|
||||
|
||||
var zInStream = new java.io.BufferedInputStream(zFile.getInputStream(entry));
|
||||
var buf = new java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, size);
|
||||
zInStream.read(buf, 0, size);
|
||||
zInStream.close();
|
||||
|
||||
if (!destPath) {
|
||||
// no filesystem destination given, so return
|
||||
// the byte array containing the extracted data
|
||||
return buf;
|
||||
}
|
||||
// extract the file to the given path
|
||||
var dest = new java.io.File(destPath, entry.getName());
|
||||
if (entry.isDirectory())
|
||||
dest.mkdirs();
|
||||
else if (buf) {
|
||||
if (!dest.getParentFile().exists())
|
||||
dest.getParentFile().mkdirs();
|
||||
try {
|
||||
var outStream = new java.io.BufferedOutputStream(new java.io.FileOutputStream(dest));
|
||||
outStream.write(buf, 0, size);
|
||||
} finally {
|
||||
outStream.close();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Private method for adding a single file to the Zip archive
|
||||
* represented by this helma.Zip instance
|
||||
* @param {java.util.zip.ZipOutputStream} zOutStream The output
|
||||
* stream to write to
|
||||
* @param {java.io.File} f The file that should be added to the
|
||||
* Zip archive.
|
||||
* @param {Number} level The compression-level between 0-9.
|
||||
* @param {String} pathPrefix The path of the directory within the
|
||||
* Zip archive where the file should be added (optional).
|
||||
* @private
|
||||
*/
|
||||
var addFile = function(zOutStream, f, level, pathPrefix) {
|
||||
var fInStream = new java.io.BufferedInputStream(new java.io.FileInputStream(f));
|
||||
buf = new java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, f.length());
|
||||
fInStream.read(buf, 0, f.length());
|
||||
|
||||
var name = new java.lang.StringBuffer();
|
||||
if (pathPrefix) {
|
||||
// append clean pathPrefix to name buffer
|
||||
var st = new java.util.StringTokenizer(pathPrefix, "\\/");
|
||||
while (st.hasMoreTokens()) {
|
||||
name.append(st.nextToken());
|
||||
name.append("/");
|
||||
}
|
||||
}
|
||||
name.append(f.getName());
|
||||
var entry = new java.util.zip.ZipEntry(name.toString());
|
||||
entry.setSize(f.length());
|
||||
entry.setTime(f.lastModified());
|
||||
zOutStream.setLevel(level);
|
||||
zOutStream.putNextEntry(entry);
|
||||
zOutStream.write(buf, 0, buf.length);
|
||||
zOutStream.closeEntry();
|
||||
fInStream.close();
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Private helper method that converts the argument into
|
||||
* an instance of java.io.File.
|
||||
* @param {helma.File|java.io.File} f Either a file object or
|
||||
* the path to a file as string
|
||||
* @return The argument converted into a file object
|
||||
* @type java.io.File
|
||||
* @private
|
||||
*/
|
||||
var evalFile = function(f) {
|
||||
var result;
|
||||
if (f instanceof java.io.File) {
|
||||
result = f;
|
||||
} else if (f instanceof helma.File || typeof(f) == "string") {
|
||||
result = new java.io.File(f);
|
||||
}
|
||||
if (!result.exists()) {
|
||||
throw "Error creating Zip Object: File '" + f + "' doesn't exist.";
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an array containing the entries of the archive
|
||||
* represented by this helma.Zip instance.
|
||||
* @returns The entries stored in the zip archive
|
||||
* @type helma.Zip.Content
|
||||
*/
|
||||
this.list = function() {
|
||||
var result = new helma.Zip.Content();
|
||||
var zFile = new java.util.zip.ZipFile(file);
|
||||
var entries = zFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
result.add(new helma.Zip.Entry(entries.nextElement()));
|
||||
}
|
||||
zFile.close();
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts a single file from the zip archive represented
|
||||
* by this helma.Zip instance. If a destination path is given it
|
||||
* writes the extracted data directly to disk using the
|
||||
* name of the zip entry, otherwise the resulting entry object
|
||||
* contains the extracted data in the property <code>data</code>.
|
||||
* @param {String} name The name of the file to extract
|
||||
* @param {String} destPath An optional destination path where
|
||||
* the extracted file should be stored.
|
||||
* @returns An object containing the entry's properties
|
||||
* @type helma.Zip.Entry
|
||||
* @see helma.Zip.Entry
|
||||
*/
|
||||
this.extract = function(name, destPath) {
|
||||
var zFile = new java.util.zip.ZipFile(file);
|
||||
var entry = zFile.getEntry(name);
|
||||
if (!entry)
|
||||
return null;
|
||||
var result = new helma.Zip.Entry(entry);
|
||||
result.data = extractEntry(zFile, entry, destPath);
|
||||
zFile.close();
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts all files within the zip archive represented by
|
||||
* this helma.Zip instance. If a destination path is given it
|
||||
* stores the files directly on disk, while preserving any directory
|
||||
* structure within the archive. If no destination path is given,
|
||||
* the resulting entry objects will contain the extracted data
|
||||
* in their property <code>data</code>.
|
||||
* @param {String} destPath An optional destination path where the
|
||||
* files in the zip archive should be stored.
|
||||
* @returns An object containing the extracted entries.
|
||||
* @type helma.Zip.Content
|
||||
* @see helma.Zip.Entry
|
||||
*/
|
||||
this.extractAll = function(destPath) {
|
||||
var result = new helma.Zip.Content();
|
||||
var zFile = new java.util.zip.ZipFile(file);
|
||||
var entries = zFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
var entry = entries.nextElement();
|
||||
var e = new helma.Zip.Entry(entry);
|
||||
e.data = extractEntry(zFile, entry, destPath);
|
||||
result.add(e);
|
||||
}
|
||||
zFile.close();
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a single file or a whole directory (recursive!) to the zip archive
|
||||
* @param {helma.File|java.io.File|String} f Either a file object
|
||||
* or the path to a file or directory on disk that should be added to the
|
||||
* archive. If the argument represents a directory, its contents will be added
|
||||
* <em>recursively</em> to the archive.
|
||||
* @param {Number} level An optional compression level to use. The argument
|
||||
* must be between zero and 9 (default: 9 = best compression).
|
||||
* @param {String} pathPrefix An optional path prefix to use within the archive.
|
||||
*/
|
||||
this.add = function (f, level, pathPrefix) {
|
||||
var f = evalFile(f);
|
||||
|
||||
// evaluate arguments
|
||||
if (arguments.length == 2) {
|
||||
if (typeof arguments[1] == "string") {
|
||||
pathPrefix = arguments[1];
|
||||
level = 9;
|
||||
} else {
|
||||
level = parseInt(arguments[1], 10);
|
||||
pathPrefix = null;
|
||||
}
|
||||
} else if (level == null || isNaN(level)) {
|
||||
level = 9;
|
||||
}
|
||||
// only levels between 0 and 9 are allowed
|
||||
level = Math.max(0, Math.min(9, level));
|
||||
|
||||
if (f.isDirectory()) {
|
||||
// add a whole directory to the zip file (recursive!)
|
||||
var files = (new helma.File(f.getAbsolutePath())).listRecursive();
|
||||
for (var i in files) {
|
||||
var fAdd = new java.io.File(files[i]);
|
||||
if (!fAdd.isDirectory()) {
|
||||
var p = fAdd.getPath().substring(f.getAbsolutePath().length, fAdd.getParent().length);
|
||||
if (pathPrefix)
|
||||
p = pathPrefix + p;
|
||||
addFile(zOutStream, fAdd, level, p);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addFile(zOutStream, f, level, pathPrefix);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a new entry to the zip file.
|
||||
* @param {ByteArray} buf A byte array containing the data to add
|
||||
* to the archive.
|
||||
* @param {String} name The name of the file to add, containing
|
||||
* an optional path prefix
|
||||
* @param {Number} level The compression level to use (0-9, defaults to 9).
|
||||
*/
|
||||
this.addData = function(buf, name, level) {
|
||||
var entry = new java.util.zip.ZipEntry(name);
|
||||
entry.setSize(buf.length);
|
||||
entry.setTime(new Date());
|
||||
if (level == null || isNaN(level)) {
|
||||
zOutStream.setLevel(9);
|
||||
} else {
|
||||
zOutStream.setLevel(Math.max(0, Math.min(9, parseInt(level, 10))));
|
||||
}
|
||||
zOutStream.putNextEntry(entry);
|
||||
zOutStream.write(buf, 0, buf.length);
|
||||
zOutStream.closeEntry();
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Closes the zip archive. This method should be called when
|
||||
* all operations have been finished, to ensure that no open
|
||||
* file handles are left.
|
||||
*/
|
||||
this.close = function() {
|
||||
zOutStream.close();
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the binary data of the zip archive.
|
||||
* @returns A ByteArray containing the binary data of the zip archive
|
||||
* @type ByteArray
|
||||
*/
|
||||
this.getData = function() {
|
||||
return bOutStream.toByteArray();
|
||||
};
|
||||
|
||||
/**
|
||||
* Saves the archive.
|
||||
* @param {String} dest The full destination path including the name
|
||||
* where the zip archive should be saved.
|
||||
*/
|
||||
this.save = function(dest) {
|
||||
if (!dest)
|
||||
throw new Error("no destination for ZipFile given");
|
||||
// first of all, close the ZipOutputStream
|
||||
zOutStream.close();
|
||||
var destFile = new java.io.File(dest);
|
||||
try {
|
||||
var outStream = new java.io.FileOutputStream(destFile);
|
||||
bOutStream.writeTo(outStream);
|
||||
} finally {
|
||||
outStream.close();
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
this.toString = function() {
|
||||
if (file) {
|
||||
return "[helma.Zip " + file.getAbsolutePath() + "]";
|
||||
} else {
|
||||
return "[helma.Zip]";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* constructor body
|
||||
*/
|
||||
var bOutStream = new java.io.ByteArrayOutputStream();
|
||||
var zOutStream = new java.util.zip.ZipOutputStream(bOutStream);
|
||||
if (file) {
|
||||
file = evalFile(file);
|
||||
}
|
||||
|
||||
for (var i in this)
|
||||
this.dontEnum(i);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new helma.Zip.Content instance
|
||||
* @class Instances of this class represent the content
|
||||
* of a zip archive.
|
||||
* @constructor
|
||||
* @returns A newly created instance of helma.Zip.Content
|
||||
*/
|
||||
helma.Zip.Content = function() {
|
||||
/**
|
||||
* The table of contents of the archive
|
||||
* @type Array
|
||||
*/
|
||||
this.toc = [];
|
||||
|
||||
/**
|
||||
* The files contained in the zip archive, where
|
||||
* each directory level is a separate object containing
|
||||
* the entries (files and directories) as properties.
|
||||
*/
|
||||
this.files = {};
|
||||
|
||||
/**
|
||||
* Adds a zip entry object to the table of contents
|
||||
* and the files collection
|
||||
* @param {helma.Zip.Entry} entry The entry to add to the
|
||||
* zip archive
|
||||
*/
|
||||
this.add = function(entry) {
|
||||
// add the file to the table of contents array
|
||||
this.toc[this.toc.length] = entry;
|
||||
// plus add it to the files tree
|
||||
var arr = entry.name.split(/[\\\/]/);
|
||||
var cnt = 0;
|
||||
var curr = this.files;
|
||||
var propName;
|
||||
while (cnt < arr.length-1) {
|
||||
propName = arr[cnt++];
|
||||
if (!curr[propName]) {
|
||||
curr[propName] = {};
|
||||
}
|
||||
curr = curr[propName];
|
||||
}
|
||||
curr[arr[cnt]] = entry;
|
||||
return;
|
||||
};
|
||||
|
||||
for (var i in this)
|
||||
this.dontEnum(i);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/** @ignore */
|
||||
helma.Zip.Content.prototype.toString = function() {
|
||||
return "[helma.Zip.Content]";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of helma.Zip.Entry
|
||||
* @class Instances of this class represent a single zip archive entry,
|
||||
* containing the (meta)data of the entry.
|
||||
* @param {java.util.zip.ZipEntry} entry The zip entry object whose metadata
|
||||
* should be stored in this instance
|
||||
* @constructor
|
||||
* @returns A newly created helma.Zip.Entry instance.
|
||||
*/
|
||||
helma.Zip.Entry = function(entry) {
|
||||
/**
|
||||
* The name of the zip archive entry
|
||||
* @type String
|
||||
*/
|
||||
this.name = entry.getName();
|
||||
|
||||
/**
|
||||
* The size of the entry in bytes
|
||||
* @type Number
|
||||
*/
|
||||
this.size = entry.getSize();
|
||||
|
||||
/**
|
||||
* The file date of the entry
|
||||
* @type Date
|
||||
*/
|
||||
this.time = entry.getTime() ? new Date(entry.getTime()) : null;
|
||||
|
||||
/**
|
||||
* True if the entry is a directory, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
this.isDirectory = entry.isDirectory();
|
||||
|
||||
/**
|
||||
* The data of the zip entry
|
||||
* @type ByteArray
|
||||
*/
|
||||
this.data = null;
|
||||
|
||||
for (var i in this)
|
||||
this.dontEnum(i);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/** @ignore */
|
||||
helma.Zip.Entry.prototype.toString = function() {
|
||||
return "[helma.Zip.Entry]";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extracts all files in the zip archive data passed as argument
|
||||
* and returns them.
|
||||
* @param {ByteArray} zipData A ByteArray containing the data of the zip archive
|
||||
* @returns The entries of the zip archive
|
||||
* @type helma.Zip.Content
|
||||
*/
|
||||
helma.Zip.extractData = function(zipData) {
|
||||
var zInStream = new java.util.zip.ZipInputStream(new java.io.ByteArrayInputStream(zipData));
|
||||
var result = new helma.Zip.Content();
|
||||
|
||||
var entry;
|
||||
while ((entry = zInStream.getNextEntry()) != null) {
|
||||
var eParam = new helma.Zip.Entry(entry);
|
||||
if (eParam.isDirectory)
|
||||
continue;
|
||||
if (eParam.size == -1)
|
||||
eParam.size = 16384;
|
||||
var bos = new java.io.ByteArrayOutputStream(eParam.size);
|
||||
var buf = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 8192);
|
||||
var count;
|
||||
while ((count = zInStream.read(buf)) != -1)
|
||||
bos.write(buf, 0, count);
|
||||
eParam.data = bos.toByteArray();
|
||||
eParam.size = bos.size();
|
||||
result.add(eParam);
|
||||
}
|
||||
zInStream.close();
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
helma.lib = "Zip";
|
||||
helma.dontEnum(helma.lib);
|
||||
for (var i in helma[helma.lib])
|
||||
helma[helma.lib].dontEnum(i);
|
||||
for (var i in helma[helma.lib].prototype)
|
||||
helma[helma.lib].prototype.dontEnum(i);
|
||||
delete helma.lib;
|
34
modules/helma/all.js
Normal file
34
modules/helma/all.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Helma License Notice
|
||||
*
|
||||
* The contents of this file are subject to the Helma License
|
||||
* Version 2.0 (the "License"). You may not use this file except in
|
||||
* compliance with the License. A copy of the License is available at
|
||||
* http://adele.helma.org/download/helma/license.txt
|
||||
*
|
||||
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
||||
*
|
||||
* $RCSfile: Aspects.js,v $
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*/
|
||||
|
||||
// convenience SingleFileRepository to load all the
|
||||
// Javascript library files in ./modules/helma
|
||||
|
||||
app.addRepository('modules/helma/Aspects.js');
|
||||
app.addRepository('modules/helma/Chart.js');
|
||||
app.addRepository('modules/helma/Color.js');
|
||||
app.addRepository('modules/helma/Database.js');
|
||||
app.addRepository('modules/helma/File.js');
|
||||
app.addRepository('modules/helma/Ftp.js');
|
||||
app.addRepository('modules/helma/Html.js');
|
||||
app.addRepository('modules/helma/Http.js');
|
||||
app.addRepository('modules/helma/Image.js');
|
||||
app.addRepository('modules/helma/Mail.js');
|
||||
app.addRepository('modules/helma/Search.js');
|
||||
app.addRepository('modules/helma/Skin.js');
|
||||
app.addRepository('modules/helma/Ssh.js');
|
||||
app.addRepository('modules/helma/Url.js');
|
||||
app.addRepository('modules/helma/Zip.js');
|
BIN
modules/helma/ganymed-ssh2.jar
Normal file
BIN
modules/helma/ganymed-ssh2.jar
Normal file
Binary file not shown.
BIN
modules/helma/jxl.jar
Normal file
BIN
modules/helma/jxl.jar
Normal file
Binary file not shown.
BIN
modules/helma/lucene-analyzers.jar
Normal file
BIN
modules/helma/lucene-analyzers.jar
Normal file
Binary file not shown.
BIN
modules/helma/lucene-core.jar
Normal file
BIN
modules/helma/lucene-core.jar
Normal file
Binary file not shown.
17
modules/summary.txt
Normal file
17
modules/summary.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
<p>HelmaLib is organized into two groups of modules:</p>
|
||||
|
||||
<ul>
|
||||
<li>modules/core which contains extensions to core JavaScript types such as
|
||||
Object, Array, or Date.</li>
|
||||
<li>modules/helma which provides new functionality to JavaScript, usually by
|
||||
wrapping a Java library.</li>
|
||||
</ul>
|
||||
|
||||
<p>To use a HelmaLib module in your Helma application, you need to add it to the
|
||||
app's repositories. The simplest way to do so is by using the app.addRepository()
|
||||
function:</p>
|
||||
|
||||
<pre> app.addRepository("modules/helma/Search.js");</pre>
|
||||
|
||||
<p>If you are looking for more Helma libraries, be sure to check out the
|
||||
<a href="https://opensvn.csie.org/traccgi/jala/wiki">Jala project</a>!</p>
|
10
modules/test/README.txt
Normal file
10
modules/test/README.txt
Normal 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.
|
33
modules/test/code/Global/global.js
Executable file
33
modules/test/code/Global/global.js
Executable 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();
|
||||
}
|
1
modules/test/code/Global/subskins.skin
Executable file
1
modules/test/code/Global/subskins.skin
Executable file
|
@ -0,0 +1 @@
|
|||
mainskin<% #subskin1 %>subskin1<% #subskin2 %>subskin2<% #end %>
|
40
modules/test/code/Organisation/type.properties
Normal file
40
modules/test/code/Organisation/type.properties
Normal 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)
|
17
modules/test/code/Person/type.properties
Normal file
17
modules/test/code/Person/type.properties
Normal 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
modules/test/code/Root/root.js
Executable file
35
modules/test/code/Root/root.js
Executable 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;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue