Merge remote-tracking branch 'modules/master' into subtree

this merges the master head of https://github.com/helma-org/apps-modules-mirror into helma
This commit is contained in:
Simon Oberhammer 2012-03-27 11:46:35 +02:00
commit 226552bc24
53 changed files with 12023 additions and 0 deletions

145
modules/helma/Aspects.js Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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>&lt;table&gt;</code> tag</li>
* <li><code>tr</code>: Attributes to render within each <code>&lt;tr&gt;</code> tag</li>
* <li><code>td</code>: Attributes to render within each <code>&lt;td&gt;</code> tag</li>
* <li><code>th</code>: Attributes to render within each <code>&lt;th&gt;</code> tag</li>
* <li><code>trHead</code>: Attributes to render within each <code>&lt;tr&gt;</code> tag
in the header area of the table</li>
* <li><code>trEven</code>: Attributes to render within each even <code>&lt;tr&gt;</code> tag</li>
* <li><code>trOdd</code>: Attributes to render within each odd <code>&lt;tr&gt;</code> tag</li>
* <li><code>tdEven</code>: Attributes to render within each even <code>&lt;td&gt;</code> tag</li>
* <li><code>tdOdd</code>: Attributes to render within each odd <code>&lt;td&gt;</code> tag</li>
* <li><code>thEven</code>: Attributes to render within each even <code>&lt;th&gt;</code> tag</li>
* <li><code>thOdd</code>: Attributes to render within each odd <code>&lt;th&gt;</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>&lt;th&gt;</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
View 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
View 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
View 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.
* &nbsp;
* 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

File diff suppressed because it is too large Load diff

124
modules/helma/Skin.js Normal file
View 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
View 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
View 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
View 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
View 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');

Binary file not shown.

BIN
modules/helma/jxl.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.