chg: replaced ant with gradle
This commit is contained in:
parent
ced560f0c7
commit
7eebeee1d0
615 changed files with 87626 additions and 638 deletions
1
modules/jala/code/.jsdoc/summary.html
Normal file
1
modules/jala/code/.jsdoc/summary.html
Normal file
|
@ -0,0 +1 @@
|
|||
Jala is a <a href="http://helma.org">Helma</a>-based library and utility project initially developed to ease the work at <a href="http://orf.at">ORF.at</a>'s software development department.
|
175
modules/jala/code/AsyncRequest.js
Normal file
175
modules/jala/code/AsyncRequest.js
Normal file
|
@ -0,0 +1,175 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the jala.AsyncRequest class.
|
||||
*/
|
||||
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new AsyncRequest instance.
|
||||
* @class This class is used to create requests of type "INTERNAL"
|
||||
* (like cron-jobs) that are processed in a separate thread and
|
||||
* therefor asynchronous.
|
||||
* @param {Object} obj Object in whose context the method should be called
|
||||
* @param {String} funcName Name of the function to call
|
||||
* @param {Array} args Array containing the arguments that should be passed
|
||||
* to the function (optional). This option is <em>deprecated</em>, instead
|
||||
* pass the arguments directly to the {@link #run} method.
|
||||
* @constructor
|
||||
* @returns A new instance of AsyncRequest
|
||||
* @type AsyncRequest
|
||||
* @deprecated Use the {@link http://helma.zumbrunn.net/reference/core/app.html#invokeAsync
|
||||
* app.invokeAsync} method instead (built-in into Helma as
|
||||
* of version 1.6)
|
||||
*/
|
||||
jala.AsyncRequest = function(obj, funcName, args) {
|
||||
app.logger.warn("Use of jala.AsyncRequest is deprecated in this version.");
|
||||
app.logger.warn("This module will probably be removed in a " +
|
||||
"future version of Jala.");
|
||||
|
||||
/**
|
||||
* Contains a reference to the thread started by this AsyncRequest
|
||||
* @type java.lang.Thread
|
||||
* @private
|
||||
*/
|
||||
var thread;
|
||||
|
||||
/**
|
||||
* Contains the timeout defined for this AsyncRequest (in milliseconds)
|
||||
* @type Number
|
||||
* @private
|
||||
*/
|
||||
var timeout;
|
||||
|
||||
/**
|
||||
* Contains the number of milliseconds to wait before starting
|
||||
* the asynchronous request.
|
||||
* @type Number
|
||||
* @private
|
||||
*/
|
||||
var delay;
|
||||
|
||||
/**
|
||||
* Run method necessary to implement java.lang.Runnable.
|
||||
* @private
|
||||
*/
|
||||
var runner = function() {
|
||||
// evaluator that will handle the request
|
||||
var ev = app.__app__.getEvaluator();
|
||||
|
||||
if (delay != null) {
|
||||
java.lang.Thread.sleep(delay);
|
||||
}
|
||||
try {
|
||||
if (args === undefined || args === null || args.constructor != Array) {
|
||||
args = [];
|
||||
}
|
||||
if (timeout != null) {
|
||||
ev.invokeInternal(obj, funcName, args, timeout);
|
||||
} else {
|
||||
ev.invokeInternal(obj, funcName, args);
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore it, but log it
|
||||
app.log("[Runner] Caught Exception: " + e);
|
||||
} finally {
|
||||
// release the ev in any case
|
||||
app.__app__.releaseEvaluator(ev);
|
||||
// remove reference to underlying thread
|
||||
thread = null;
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the timeout of this asynchronous request.
|
||||
* @param {Number} seconds Thread-timeout.
|
||||
*/
|
||||
this.setTimeout = function(seconds) {
|
||||
timeout = seconds * 1000;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines the delay to wait before evaluating this asynchronous request.
|
||||
* @param {Number} millis Milliseconds to wait
|
||||
*/
|
||||
this.setDelay = function(millis) {
|
||||
delay = millis;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Starts this asynchronous request. Any arguments passed to
|
||||
* this method will be passed to the method executed by
|
||||
* this AsyncRequest instance.
|
||||
*/
|
||||
this.run = function() {
|
||||
if (arguments.length > 0) {
|
||||
// convert arguments object into array
|
||||
args = Array.prototype.slice.call(arguments, 0, arguments.length);
|
||||
}
|
||||
thread = (new java.lang.Thread(new java.lang.Runnable({"run": runner})));
|
||||
thread.start();
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Starts this asynchronous request.
|
||||
* @deprecated Use {@link #run} instead
|
||||
*/
|
||||
this.evaluate = function() {
|
||||
this.run.apply(this, arguments);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the underlying thread is alive
|
||||
* @returns True if the underlying thread is alive,
|
||||
* false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
this.isAlive = function() {
|
||||
return thread != null && thread.isAlive();
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
this.toString = function() {
|
||||
return "[jala.AsyncRequest]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Main constructor body
|
||||
*/
|
||||
if (!obj || !funcName)
|
||||
throw "jala.AsyncRequest: insufficient arguments.";
|
||||
return this;
|
||||
}
|
429
modules/jala/code/BitTorrent.js
Normal file
429
modules/jala/code/BitTorrent.js
Normal file
|
@ -0,0 +1,429 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the jala.BitTorrent class.
|
||||
*/
|
||||
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Module dependencies
|
||||
*/
|
||||
app.addRepository("modules/core/String.js");
|
||||
app.addRepository("modules/helma/File.js");
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new BitTorrent file.
|
||||
* @class This class provides methods to create a BitTorrent
|
||||
* metadata file from any desired file.
|
||||
* @param {String} trackerUrl The URL string of the tracker.
|
||||
* @param {String} filePath The path to the original file.
|
||||
* @returns A new BitTorrent file.
|
||||
* @constructor
|
||||
*/
|
||||
jala.BitTorrent = function(filePath, trackerUrl) {
|
||||
var self = this;
|
||||
self.arguments = arguments;
|
||||
|
||||
// FIXME: Add support for multitracker mode as specified in
|
||||
// http://www.bittornado.com/docs/multitracker-spec.txt
|
||||
|
||||
var torrent, sourceFile, torrentFile;
|
||||
var pieceLength = 256;
|
||||
|
||||
var updateTorrent = function() {
|
||||
if (torrent.info) {
|
||||
return torrent;
|
||||
}
|
||||
|
||||
var file = new java.io.File(filePath);
|
||||
if (!file.exists()) {
|
||||
throw Error("File " + file + " does not exist!");
|
||||
}
|
||||
|
||||
var md5 = java.security.MessageDigest.getInstance("MD5");
|
||||
var sha1 = java.security.MessageDigest.getInstance("SHA-1");
|
||||
|
||||
var fis = new java.io.FileInputStream(file);
|
||||
var bis = new java.io.BufferedInputStream(fis);
|
||||
var cache = new java.io.ByteArrayOutputStream();
|
||||
|
||||
var pieces = [];
|
||||
var length = pieceLength * 1024;
|
||||
var buffer = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, length);
|
||||
|
||||
while (bis.read(buffer, 0, buffer.length) > -1) {
|
||||
app.debug("Updating SHA-1 hash with " + buffer.length + " bytes");
|
||||
sha1.reset();
|
||||
sha1["update(byte[])"](buffer);
|
||||
cache["write(byte[])"](buffer);
|
||||
pieces.push(new java.lang.String(sha1.digest()));
|
||||
}
|
||||
|
||||
bis.close();
|
||||
fis.close();
|
||||
|
||||
torrent.info = {
|
||||
//md5sum: new java.lang.String(md5.digest(cache.toByteArray())),
|
||||
length: cache.size(),
|
||||
name: file.getName(),
|
||||
"piece length": length,
|
||||
pieces: pieces.join("")
|
||||
};
|
||||
|
||||
return torrent;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all available property names.
|
||||
* @returns The list of property names.
|
||||
* @type Array
|
||||
*/
|
||||
this.keys = function() {
|
||||
var keys = [];
|
||||
for (var i in torrent) {
|
||||
keys.push(i);
|
||||
}
|
||||
keys.sort();
|
||||
return keys;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a torrent property.
|
||||
* @param {String} name The name of the property.
|
||||
* @returns The value of the property.
|
||||
*/
|
||||
this.get = function(name) {
|
||||
return torrent[name];
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a torrent property.
|
||||
* @param {String} name The name of the property.
|
||||
* @param {Object} value The property's value.
|
||||
*/
|
||||
this.set = function(name, value) {
|
||||
if (typeof torrent[name] == "undefined") {
|
||||
throw Error("Cannot set torrent property " + name);
|
||||
}
|
||||
torrent[name] = value;
|
||||
delete torrent.info;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the creation date of the torrent.
|
||||
* @returns The torrent's creation date.
|
||||
* @type Date
|
||||
*/
|
||||
this.getCreationDate = function() {
|
||||
return new Date(torrent["creation date"] * 1000);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the creation date of the torrent.
|
||||
* @param {Date} date The desired creation date.
|
||||
*/
|
||||
this.setCreationDate = function(date) {
|
||||
this.set("creation date", Math.round((date || new Date()).getTime() / 1000));
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the piece length of the torrent.
|
||||
* @returns The torrent's piece length.
|
||||
* @type Number
|
||||
*/
|
||||
this.getPieceLength = function() {
|
||||
return pieceLength;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the piece length of the torrent.
|
||||
* @param {Number} length The desired piece length.
|
||||
*/
|
||||
this.setPieceLength = function(length) {
|
||||
pieceLength = length;
|
||||
delete torrent.info;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the underlying torrent file.
|
||||
* @returns The torrent file.
|
||||
* @type helma.File
|
||||
*/
|
||||
this.getTorrentFile = function() {
|
||||
return torrentFile;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the underlying source file.
|
||||
* @returns The source file.
|
||||
* @type helma.File
|
||||
*/
|
||||
this.getSourceFile = function() {
|
||||
return sourceFile;
|
||||
};
|
||||
|
||||
/**
|
||||
* Saves the torrent as file.
|
||||
* @param {String} filename An optional name for the torrent file.
|
||||
* If no name is given it will be composed from name of source
|
||||
* file as defined in the torrent plus the ending ".torrent".
|
||||
*/
|
||||
this.save = function(filename) {
|
||||
updateTorrent();
|
||||
if (!filename) {
|
||||
filename = torrent.info.name + ".torrent";
|
||||
}
|
||||
torrentFile = new helma.File(sourceFile.getParent(), filename);
|
||||
torrentFile.remove();
|
||||
torrentFile.open();
|
||||
torrentFile.write(jala.BitTorrent.bencode(torrent));
|
||||
torrentFile.close();
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a string representation of the torrent.
|
||||
* @returns The torrent as string.
|
||||
* @type String
|
||||
*/
|
||||
this.toString = function() {
|
||||
return "[jala.BitTorrent " + filePath + "]";
|
||||
};
|
||||
|
||||
if (String(filePath).endsWith(".torrent")) {
|
||||
torrentFile = new helma.File(filePath);
|
||||
torrent = jala.BitTorrent.bdecode(torrentFile.readAll());
|
||||
sourceFile = new helma.File(torrent.info.name);
|
||||
} else {
|
||||
torrent = {
|
||||
announce: trackerUrl || null,
|
||||
"announce-list": null,
|
||||
"creation date": null,
|
||||
comment: null,
|
||||
"created by": null,
|
||||
};
|
||||
this.setCreationDate();
|
||||
sourceFile = new helma.File(filePath);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The bencode method. Turns an arbitrary JavaScript
|
||||
* object structure into a corresponding encoded
|
||||
* string.
|
||||
* @param {Object} obj The target JavaScript object.
|
||||
* @returns The encoded string.
|
||||
* @type String
|
||||
*/
|
||||
jala.BitTorrent.bencode = function(obj) {
|
||||
var bencode = arguments.callee;
|
||||
var str = obj.toString();
|
||||
res.push();
|
||||
switch (obj.constructor) {
|
||||
case Array:
|
||||
res.write("l");
|
||||
for (var i in obj) {
|
||||
if (obj[i])
|
||||
res.write(bencode(obj[i]));
|
||||
}
|
||||
res.write("e");
|
||||
break;
|
||||
|
||||
case Number:
|
||||
res.write("i" + str + "e");
|
||||
break;
|
||||
|
||||
case Object:
|
||||
res.write("d");
|
||||
var keys = [];
|
||||
for (var i in obj) {
|
||||
keys.push(i);
|
||||
}
|
||||
keys.sort();
|
||||
var key;
|
||||
for (var i in keys) {
|
||||
key = keys[i];
|
||||
if (obj[key]) {
|
||||
res.write(bencode(key));
|
||||
res.write(bencode(obj[key]));
|
||||
}
|
||||
}
|
||||
res.write("e");
|
||||
break;
|
||||
|
||||
default:
|
||||
res.write(str.length + ":" + str);
|
||||
}
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The bdecode method. Turns an encoded string into
|
||||
* a corresponding JavaScript object structure.
|
||||
* FIXME: Handle with caution...
|
||||
* @param {String} code The encoded string.
|
||||
* @returns The decoded JavaScript structure.
|
||||
* @type Object
|
||||
*/
|
||||
jala.BitTorrent.bdecode = function(code) {
|
||||
var DICTIONARY = "d";
|
||||
var LIST = "l";
|
||||
var INTEGER = "i";
|
||||
var STRING = "s";
|
||||
var END = "e";
|
||||
|
||||
var stack = [];
|
||||
var overflowCounter = 0;
|
||||
|
||||
var position = -1, current;
|
||||
|
||||
function getResult() {
|
||||
update();
|
||||
var result;
|
||||
switch (current) {
|
||||
case DICTIONARY:
|
||||
result = bdecodeDictionary();
|
||||
break;
|
||||
case LIST:
|
||||
result = bdecodeList();
|
||||
break;
|
||||
case INTEGER:
|
||||
result = bdecodeInteger();
|
||||
break;
|
||||
case END:
|
||||
case null:
|
||||
//res.debug("*** end detected in getResult()");
|
||||
result = null;
|
||||
break;
|
||||
default:
|
||||
result = bdecodeString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function update() {
|
||||
position += 1;
|
||||
current = code.charAt(position);
|
||||
/* res.debug("stack: " + stack);
|
||||
res.debug("position: " + position);
|
||||
res.debug("current: " + current);
|
||||
res.debug("remains: " + code.substr(position)); */
|
||||
return;
|
||||
}
|
||||
|
||||
function overflow() {
|
||||
if (overflowCounter++ > 100)
|
||||
throw Error("Error parsing bdecoded string");
|
||||
return false;
|
||||
}
|
||||
|
||||
function bdecodeDictionary() {
|
||||
stack.push(DICTIONARY);
|
||||
var dictionary = {}, key, value;
|
||||
while (current && !overflow()) {
|
||||
key = getResult();
|
||||
if (key === null)
|
||||
break;
|
||||
value = getResult();
|
||||
if (key && value)
|
||||
dictionary[key] = value;
|
||||
else
|
||||
break;
|
||||
}
|
||||
stack.pop();
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
function bdecodeList() {
|
||||
stack.push(LIST);
|
||||
var list = [], value;
|
||||
while (current && !overflow()) {
|
||||
var value = getResult();
|
||||
if (value)
|
||||
list.push(value);
|
||||
else
|
||||
break;
|
||||
}
|
||||
stack.pop();
|
||||
return list;
|
||||
}
|
||||
|
||||
function bdecodeInteger() {
|
||||
var integer = "";
|
||||
stack.push(integer);
|
||||
while (current && !overflow()) {
|
||||
update();
|
||||
if (current == "e")
|
||||
break;
|
||||
integer += current;
|
||||
}
|
||||
if (isNaN(integer))
|
||||
throw("Error in bdecoded integer: " + integer + " is not a number");
|
||||
//res.debug("integer = " + integer);
|
||||
stack.pop();
|
||||
return parseInt(integer);
|
||||
}
|
||||
|
||||
function bdecodeString() {
|
||||
var length = current, string = "";
|
||||
stack.push(string);
|
||||
update();
|
||||
while (current && current != ":" && !overflow()) {
|
||||
length += current;
|
||||
update();
|
||||
}
|
||||
if (isNaN(length))
|
||||
throw("Error in bdecoded string: invalid length " + length);
|
||||
//res.debug("length = " + length);
|
||||
length = parseInt(length);
|
||||
if (length > code.length - position)
|
||||
throw Error("Error parsing bdecoded string");
|
||||
for (var i=0; i<length; i+=1) {
|
||||
update();
|
||||
string += current;
|
||||
}
|
||||
//res.debug("string = " + string);
|
||||
if (string == "creation date")
|
||||
void(null);
|
||||
stack.pop();
|
||||
return string;
|
||||
}
|
||||
|
||||
return getResult();
|
||||
};
|
119
modules/jala/code/Captcha.js
Normal file
119
modules/jala/code/Captcha.js
Normal file
|
@ -0,0 +1,119 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the jala.Captcha class.
|
||||
*/
|
||||
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new captcha.
|
||||
* @returns A new captcha.
|
||||
* @class Wrapper class for the
|
||||
* {@link http://jcaptcha.sourceforge.net/ JCaptcha library}.
|
||||
* A captcha (an acronym for "completely automated public
|
||||
* Turing test to tell computers and humans apart") is a
|
||||
* type of challenge-response test used in computing to
|
||||
* determine whether or not the user is human.
|
||||
* @constructor
|
||||
*/
|
||||
jala.Captcha = function() {
|
||||
/**
|
||||
* Jala dependencies
|
||||
*/
|
||||
app.addRepository(getProperty("jala.dir", "modules/jala") +
|
||||
"/lib/jcaptcha-all-1.0-RC3.jar");
|
||||
|
||||
var gimpy;
|
||||
|
||||
try {
|
||||
var ref = Packages.com.octo.captcha.engine.image.gimpy;
|
||||
gimpy = ref.DefaultGimpyEngine();
|
||||
} catch(e) {
|
||||
throw("Cannot instantiate object due to missing java class: " +
|
||||
arguments.callee.toString());
|
||||
}
|
||||
var captcha = gimpy.getNextCaptcha();
|
||||
|
||||
/**
|
||||
* Get a new captcha object.
|
||||
* @returns A new captcha object.
|
||||
* @type com.octo.captcha.Captcha
|
||||
*/
|
||||
this.getCaptcha = function getCaptcha() {
|
||||
return captcha;
|
||||
};
|
||||
|
||||
/**
|
||||
* Render a new captcha image.
|
||||
*/
|
||||
this.renderImage = function renderImage() {
|
||||
var image = captcha.getImageChallenge();
|
||||
var stream = new java.io.ByteArrayOutputStream();
|
||||
var ref = Packages.com.sun.image.codec.jpeg.JPEGCodec;
|
||||
var encoder = ref.createJPEGEncoder(stream);
|
||||
encoder.encode(image);
|
||||
res.contentType = "image/jpeg";
|
||||
res.writeBinary(stream.toByteArray());
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate a user's input with the prompted captcha.
|
||||
* @param {String} input The user's input.
|
||||
* @returns True if the user's input matches the captcha.
|
||||
* @type Boolean
|
||||
*/
|
||||
this.validate = function validate(input) {
|
||||
return !input || captcha.validateResponse(input);
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get a string representation of the captcha class.
|
||||
* @returns A string representation of the capthca class.
|
||||
* @type String
|
||||
* @ignore
|
||||
*/
|
||||
jala.Captcha.toString = function toString() {
|
||||
return "[jala.Captcha http://jcaptcha.sourceforge.net]";
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get a string representation of the captcha object.
|
||||
* @returns A string representation of the captcha object.
|
||||
* @type String
|
||||
*/
|
||||
jala.Captcha.prototype.toString = function toString() {
|
||||
return "[jala.Captcha Object]";
|
||||
};
|
1121
modules/jala/code/Database.js
Normal file
1121
modules/jala/code/Database.js
Normal file
File diff suppressed because it is too large
Load diff
545
modules/jala/code/Date.js
Normal file
545
modules/jala/code/Date.js
Normal file
|
@ -0,0 +1,545 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the jala.Date class.
|
||||
*/
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* HelmaLib dependencies
|
||||
*/
|
||||
app.addRepository("modules/core/Date.js");
|
||||
app.addRepository("modules/helma/Html.js");
|
||||
|
||||
/**
|
||||
* Constructs a new Renderings object.
|
||||
* @class This class provides various convenience
|
||||
* methods for rendering purposes.
|
||||
* @constructor
|
||||
*/
|
||||
jala.Date = function() {
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a timestamp as set of DropDown boxes, following the
|
||||
* format passed as argument. Every <select>
|
||||
* item is prefixed with a string so that it can be retrieved
|
||||
* easily from the values of a submitted POST request.
|
||||
* @param {String} prefix The prefix to use for all dropdown boxes, eg. "postdate"
|
||||
* @param {Date} date A Date object to use as preselection (optional)
|
||||
* @param {Object} fmt Array containing one parameter object for every single
|
||||
* select box that should be rendered, with the following properties set:
|
||||
* <ul>
|
||||
* <li>pattern - The date format pattern that should be rendered. Valid
|
||||
* patterns are: "dd", "MM", "yyyy", "HH", "ss".</li>
|
||||
* <li>firstOption - The string to use as first option, eg.: "choose a day"</li>
|
||||
* </ul>
|
||||
*/
|
||||
jala.Date.prototype.renderEditor = function(prefix, date, fmt) {
|
||||
/**
|
||||
* rendering method
|
||||
* @private
|
||||
*/
|
||||
var render = function(param, date) {
|
||||
switch (param.pattern) {
|
||||
case "dd":
|
||||
param.offset = 1;
|
||||
param.max = 31;
|
||||
param.selected = (date ? date.getDate() : null);
|
||||
break;
|
||||
|
||||
case "MM":
|
||||
param.offset = 1;
|
||||
param.max = 12;
|
||||
param.selected = (date ? date.getMonth() +1 : null);
|
||||
break;
|
||||
|
||||
case "yyyy":
|
||||
param.offset = 2002;
|
||||
param.max = 20;
|
||||
param.selected = (date ? date.getFullYear() : null);
|
||||
break;
|
||||
|
||||
case "HH":
|
||||
param.offset = 0;
|
||||
param.max = 24;
|
||||
param.selected = (date ? date.getHours() : null);
|
||||
break;
|
||||
|
||||
case "mm":
|
||||
param.offset = 0;
|
||||
param.max = 60;
|
||||
param.selected = (date ? date.getMinutes() : null);
|
||||
break;
|
||||
|
||||
case "ss":
|
||||
param.offset = 0;
|
||||
param.max = 60;
|
||||
param.selected = (date ? date.getSeconds() : null);
|
||||
break;
|
||||
}
|
||||
|
||||
var key = prefix + ":" + param.pattern;
|
||||
if (req.data[key])
|
||||
param.selected = req.data[key];
|
||||
var options = [];
|
||||
var opt;
|
||||
for (var i=0;i<param.max;i++) {
|
||||
opt = (param.offset + i).format("00");
|
||||
options[i] = [opt, opt];
|
||||
}
|
||||
var html = new helma.Html();
|
||||
html.dropDown({name: key}, options, param.selected, param.firstOption);
|
||||
}
|
||||
|
||||
if (!fmt)
|
||||
var fmt = [{pattern: "dd", firstOption: "day"},
|
||||
{pattern: "MM", firstOption: "month"},
|
||||
{pattern: "yyyy", firstOption: "year"},
|
||||
{pattern: "HH", firstOption: "hour"},
|
||||
{pattern: "mm", firstOption: "minute"}];
|
||||
|
||||
for (var i in fmt) {
|
||||
render(fmt[i], date);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a timestamp as set of dropdown-boxes
|
||||
* @see #renderEditor
|
||||
* @type String
|
||||
*/
|
||||
jala.Date.prototype.renderEditorAsString = function(prefix, date, pattern) {
|
||||
res.push();
|
||||
this.renderEditor(prefix, date, pattern);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new instance of jala.Data.Calendar
|
||||
* @class This class represents a calendar based based on a grouped
|
||||
* collection of HopObjects. It provides several methods for rendering
|
||||
* the calendar plus defining locale and timezone settings.
|
||||
* @param {HopObject} collection A grouped HopObject collection to work on
|
||||
* @returns A newly created jala.Date.Calendar instance
|
||||
* @constructor
|
||||
*/
|
||||
jala.Date.Calendar = function(collection) {
|
||||
var renderer = null;
|
||||
var locale = java.util.Locale.getDefault();
|
||||
var timezone = java.util.TimeZone.getDefault();
|
||||
var hrefFormat = "yyyyMMdd";
|
||||
var accessNameFormat = "yyyyMMdd";
|
||||
|
||||
/**
|
||||
* Returns the collection this calendar object works on
|
||||
* @returns The HopObject collection of this calendar
|
||||
* @type HopObject
|
||||
*/
|
||||
this.getCollection = function() {
|
||||
return collection;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the renderer to use.
|
||||
* @param {Object} r The renderer to use
|
||||
* @see #getRenderer
|
||||
*/
|
||||
this.setRenderer = function(r) {
|
||||
renderer = r;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the renderer used by this calendar.
|
||||
* @returns The calendar renderer
|
||||
* @type Object
|
||||
* @see #setRenderer
|
||||
*/
|
||||
this.getRenderer = function() {
|
||||
if (!renderer) {
|
||||
renderer = new jala.Date.Calendar.Renderer(this);
|
||||
}
|
||||
return renderer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the locale to use within this calendar object
|
||||
* @param {java.util.Locale} loc The locale to use
|
||||
* @see #getLocale
|
||||
*/
|
||||
this.setLocale = function(loc) {
|
||||
locale = loc;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the locale used within this calendar instance. By default
|
||||
* the locale used by this calendar is the default locale of the
|
||||
* Java Virtual Machine running Helma.
|
||||
* @returns The locale of this calendar
|
||||
* @type java.util.Locale
|
||||
* @see #setLocale
|
||||
*/
|
||||
this.getLocale = function() {
|
||||
return locale;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the locale to use within this calendar object
|
||||
* @param {java.util.Locale} loc The locale to use
|
||||
* @see #getTimeZone
|
||||
*/
|
||||
this.setTimeZone = function(tz) {
|
||||
timezone = tz;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the locale used within this calendar instance. By default
|
||||
* the timezone used by this calendar is the default timezone
|
||||
* of the Java Virtual Machine running Helma.
|
||||
* @returns The locale of this calendar
|
||||
* @type java.util.Locale
|
||||
* @see #setTimeZone
|
||||
*/
|
||||
this.getTimeZone = function() {
|
||||
return timezone;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the format of the hrefs to render by this calendar
|
||||
* to the format pattern passed as argument.
|
||||
* @param {String} fmt The date format pattern to use for
|
||||
* rendering the href
|
||||
* @see #getHrefFormat
|
||||
*/
|
||||
this.setHrefFormat = function(fmt) {
|
||||
hrefFormat = fmt;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the date formatting pattern used to render hrefs. The default
|
||||
* format is "yyyyMMdd".
|
||||
* @returns The date formatting pattern
|
||||
* @type String
|
||||
* @see #setHrefFormat
|
||||
*/
|
||||
this.getHrefFormat = function() {
|
||||
return hrefFormat;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the format of the group name to use when trying to access
|
||||
* child objects of the collection this calendar is operating on.
|
||||
* @param {String} fmt The date format pattern to use for
|
||||
* accessing child objects
|
||||
* @see #getAccessNameFormat
|
||||
*/
|
||||
this.setAccessNameFormat = function(fmt) {
|
||||
accessNameFormat = fmt;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the format of the access name used by this calendar to access
|
||||
* child group objects of the collection this calendar is operating on.
|
||||
* The default format is "yyyyMMdd".
|
||||
* @returns The date formatting pattern used to access child objects
|
||||
* @type String
|
||||
* @see #setAccessNameFormat
|
||||
*/
|
||||
this.getAccessNameFormat = function() {
|
||||
return accessNameFormat;
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
jala.Date.Calendar.prototype.toString = function() {
|
||||
return "[Jala Calendar]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the calendar using either a custom renderer defined
|
||||
* using {@link #setRenderer} or the default one.
|
||||
* @see #setRenderer
|
||||
* @see jala.Date.Calendar.Renderer
|
||||
*/
|
||||
jala.Date.Calendar.prototype.render = function(today) {
|
||||
var renderer = this.getRenderer();
|
||||
var collection = this.getCollection();
|
||||
var hrefFormat = this.getHrefFormat();
|
||||
var accessNameFormat = this.getAccessNameFormat();
|
||||
var locale = this.getLocale();
|
||||
var timezone = this.getTimeZone();
|
||||
var size = collection.size();
|
||||
if (size == null)
|
||||
return;
|
||||
|
||||
/**
|
||||
* private method that creates a date object set
|
||||
* to the last date of the previous month or the
|
||||
* first date of the next month (if available)
|
||||
*/
|
||||
var prevNextMonth = function(which, dayIndex) {
|
||||
var obj;
|
||||
if (which == "prev") {
|
||||
if (size <= dayIndex || !(obj = collection.get(dayIndex +1)))
|
||||
return;
|
||||
} else if (which == "next") {
|
||||
if (dayIndex == 0 || !(obj = collection.get(dayIndex - 1)))
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
return new Date(obj.groupname.substring(0, 4),
|
||||
obj.groupname.substring(4, 6) -1,
|
||||
obj.groupname.substring(6));
|
||||
};
|
||||
|
||||
// create the calendar object used for date calculations
|
||||
var cal = java.util.Calendar.getInstance(timezone, locale);
|
||||
var firstDayOfWeek = cal.getFirstDayOfWeek();
|
||||
var symbols = new java.text.DateFormatSymbols(locale);
|
||||
|
||||
res.push();
|
||||
// render the header-row
|
||||
res.push();
|
||||
var weekdays = symbols.getShortWeekdays();
|
||||
for (var i=0;i<7;i++) {
|
||||
renderer.renderDayHeader(weekdays[(i+firstDayOfWeek-1)%7+1]);
|
||||
}
|
||||
renderer.renderRow(res.pop());
|
||||
|
||||
cal.set(java.util.Calendar.DATE, 1);
|
||||
|
||||
// check whether there's a day in path
|
||||
// if so, use it to determine the month to render
|
||||
if (today) {
|
||||
cal.set(java.util.Calendar.YEAR, today.getFullYear());
|
||||
cal.set(java.util.Calendar.MONTH, today.getMonth());
|
||||
}
|
||||
// nr. of empty days in rendered calendar before the first day of month appears
|
||||
var pre = (7-firstDayOfWeek+cal.get(java.util.Calendar.DAY_OF_WEEK)) % 7;
|
||||
var days = cal.getActualMaximum(java.util.Calendar.DATE);
|
||||
var weeks = Math.ceil((pre + days) / 7);
|
||||
var daycnt = 1;
|
||||
|
||||
var date = new Date(cal.get(java.util.Calendar.YEAR), cal.get(java.util.Calendar.MONTH), 1);
|
||||
// remember the index of the first and last days within this month.
|
||||
// this is needed to optimize previous and next month links.
|
||||
var lastDayIndex = Number.MAX_VALUE;
|
||||
var firstDayIndex = -1;
|
||||
|
||||
var dayObj, idx, selected;
|
||||
for (var i=0;i<weeks;i++) {
|
||||
res.push();
|
||||
for (var j=0;j<7;j++) {
|
||||
if ((i == 0 && j < pre) || daycnt > days) {
|
||||
renderer.renderDay(null);
|
||||
} else {
|
||||
date.setDate(daycnt);
|
||||
if ((dayObj = collection.get(date.format(accessNameFormat))) != null) {
|
||||
idx = collection.contains(dayObj);
|
||||
if (idx > -1) {
|
||||
if (idx > firstDayIndex) {
|
||||
firstDayIndex = idx;
|
||||
}
|
||||
if (idx < lastDayIndex) {
|
||||
lastDayIndex = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
selected = (today != null) ? date.equals(today) : false;
|
||||
renderer.renderDay(date, dayObj != null, selected);
|
||||
daycnt++;
|
||||
}
|
||||
}
|
||||
renderer.renderRow(res.pop());
|
||||
}
|
||||
var prevMonth = prevNextMonth("prev", firstDayIndex) || null;
|
||||
var nextMonth = prevNextMonth("next", lastDayIndex) || null;
|
||||
renderer.renderCalendar(date, res.pop(), prevMonth, nextMonth);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a rendered calendar
|
||||
* @see #renderCalendar
|
||||
* @type String
|
||||
*/
|
||||
jala.Date.Calendar.prototype.getCalendar = function(today) {
|
||||
res.push();
|
||||
this.render(today);
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a new instance of the default calendar renderer.
|
||||
* @class A default renderer to use in conjunction with jala.Date.Calendar
|
||||
* @param {jala.Date.Calendar} calendar The calendar utilizing this renderer
|
||||
* @returns A newly created instance of jala.Date.Calendar.Renderer
|
||||
* @constructor
|
||||
*/
|
||||
jala.Date.Calendar.Renderer = function(calendar) {
|
||||
|
||||
/**
|
||||
* An instance of helma.Html used for rendering the calendar
|
||||
* @type helma.Html
|
||||
*/
|
||||
this.html = new helma.Html();
|
||||
|
||||
/**
|
||||
* The calendar utilizing this renderer instance
|
||||
* @type jala.Date.Calendar
|
||||
*/
|
||||
this.calendar = calendar;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
jala.Date.Calendar.Renderer.prototype.toString = function() {
|
||||
return "[Jala Calendar Default Renderer]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a single cell in the calendar day header row directly to response.
|
||||
* @param {String} text The text to display in the header field.
|
||||
*/
|
||||
jala.Date.Calendar.Renderer.prototype.renderDayHeader = function(text) {
|
||||
this.html.element("th", text);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a single calendar row directly to response.
|
||||
* @param {String} row The body of the calendar row.
|
||||
*/
|
||||
jala.Date.Calendar.Renderer.prototype.renderRow = function(row) {
|
||||
this.html.element("tr", row);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a single day within the calendar directly to response.
|
||||
* @param {Date} date A date instance representing the day within the calendar.
|
||||
* @param {Boolean} isExisting True if there is a child object in the calendar's
|
||||
* collection to which the date cell should link to
|
||||
* @param {Boolean} isSelected True if this calendar day should be rendered
|
||||
* as selected day.
|
||||
*/
|
||||
jala.Date.Calendar.Renderer.prototype.renderDay = function(date, isExisting, isSelected) {
|
||||
var attr = {"class": "jala-calendar-day day"};
|
||||
if (isSelected === true) {
|
||||
attr["class"] += " jala-calendar-selected selected";
|
||||
}
|
||||
this.html.openTag("td", attr);
|
||||
if (date != null) {
|
||||
var text = date.getDate();
|
||||
if (isExisting === true) {
|
||||
attr = {"href": this.calendar.getCollection().href() +
|
||||
date.format(this.calendar.getHrefFormat())};
|
||||
this.html.link(attr, text);
|
||||
} else {
|
||||
res.write(text);
|
||||
}
|
||||
}
|
||||
this.html.closeTag("td");
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a link to the previous or next month's calendar directly to response.
|
||||
* @param {Date} date A date object set to the previous or next available
|
||||
* month. This can be null in case there is no previous or next month.
|
||||
*/
|
||||
jala.Date.Calendar.Renderer.prototype.renderPrevNextLink = function(date) {
|
||||
if (date != null) {
|
||||
var attr = {"href": this.calendar.getCollection().href() +
|
||||
date.format(this.calendar.getHrefFormat())};
|
||||
this.html.link(attr, date.format("MMMM", this.calendar.getLocale()));
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the calendar directly to response.
|
||||
* @param {Date} date A date object representing this calendar's month and year.
|
||||
* Please mind that the day will be set to the <em>last</em> date in this
|
||||
* month.
|
||||
* @param {String} body The rendered calendar weeks including the day header
|
||||
* (basically the whole kernel of the table).
|
||||
* @param {Date} prevMonth A date object set to the last available date of
|
||||
* the previous month. This can be used to render a navigation link to
|
||||
* the previous month.
|
||||
* @param {Date} nextMonth A date object set to the first available date
|
||||
* of the next month. This can be used to render a navigation link to
|
||||
* the next month.
|
||||
*/
|
||||
jala.Date.Calendar.Renderer.prototype.renderCalendar = function(date, body, prevMonth, nextMonth) {
|
||||
var locale = this.calendar.getLocale();
|
||||
this.html.openTag("table", {"class": "jala-calendar calendar"});
|
||||
this.html.openTag("thead");
|
||||
this.html.openTag("tr");
|
||||
this.html.openTag("th", {"colspan": 7});
|
||||
res.write(date.format("MMMM", locale));
|
||||
res.write(' ');
|
||||
res.write(date.format("yyyy", locale));
|
||||
this.html.closeTag("th");
|
||||
this.html.closeTag("tr");
|
||||
this.html.closeTag("thead");
|
||||
this.html.element("tbody", body);
|
||||
this.html.openTag("tfoot");
|
||||
this.html.openTag("tr");
|
||||
this.html.openTag("td", {"class": "jala-calendar-left left", "colspan": 3});
|
||||
this.renderPrevNextLink(prevMonth);
|
||||
this.html.closeTag("td");
|
||||
this.html.openTag("td");
|
||||
this.html.closeTag("td");
|
||||
this.html.openTag("td", {"class": "jala-calendar-right right", "colspan": 3});
|
||||
this.renderPrevNextLink(nextMonth);
|
||||
this.html.closeTag("td");
|
||||
this.html.closeTag("tr");
|
||||
this.html.closeTag("tfoot");
|
||||
this.html.closeTag("table");
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default date class instance.
|
||||
* @type jala.Date
|
||||
* @final
|
||||
*/
|
||||
jala.date = new jala.Date();
|
312
modules/jala/code/DnsClient.js
Normal file
312
modules/jala/code/DnsClient.js
Normal file
|
@ -0,0 +1,312 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the jala.DnsClient class.
|
||||
*/
|
||||
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Jala dependencies
|
||||
*/
|
||||
app.addRepository(getProperty("jala.dir", "modules/jala") +
|
||||
"/lib/javadns.jar");
|
||||
|
||||
/**
|
||||
* Constructs a new DnsClient object.
|
||||
* @class This is a wrapper around the Dns Client by wonderly.org
|
||||
* providing methods for querying Dns servers. For more information
|
||||
* about the Java DNS client visit
|
||||
* <a href="https://javadns.dev.java.net/">https://javadns.dev.java.net/</a>.
|
||||
* Please mind that the nameserver specified must accept queries on port
|
||||
* 53 TCP (the Java DNS client used doesn't support UDP nameserver queries),
|
||||
* and that reverse lookups are not supported.
|
||||
* @param {String} nameServer IP-Address or FQDN of nameserver to query
|
||||
* @constructor
|
||||
*/
|
||||
jala.DnsClient = function(nameServer) {
|
||||
/**
|
||||
* Contains the IP Adress/FQDN of the name server to query.
|
||||
* @type String
|
||||
*/
|
||||
this.nameServer = nameServer;
|
||||
|
||||
if (!this.nameServer) {
|
||||
throw "jala.DnsClient: missing nameserver argument";
|
||||
} else {
|
||||
// test if required javadns library is available
|
||||
try {
|
||||
var clazz = java.lang.Class.forName("org.wonderly.net.dns.Query",
|
||||
false, app.getClassLoader())
|
||||
} catch (e) {
|
||||
throw "jala.DnsClient requires JavaDNS.jar"
|
||||
+ " in lib/ext or application directory "
|
||||
+ "[https://javadns.dev.java.net/]";
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
jala.DnsClient.PKG = Packages.org.wonderly.net.dns;
|
||||
|
||||
/**
|
||||
* The "A" record/query type.
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.DnsClient.TYPE_A = jala.DnsClient.PKG.Question.TYPE_A;
|
||||
|
||||
/**
|
||||
* The "CNAME" record/query type.
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.DnsClient.TYPE_CNAME = jala.DnsClient.PKG.Question.TYPE_CNAME;
|
||||
|
||||
/**
|
||||
* The "MX" record/query type.
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.DnsClient.TYPE_MX = jala.DnsClient.PKG.Question.TYPE_MX;
|
||||
|
||||
/**
|
||||
* The "NS" record/query type.
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.DnsClient.TYPE_NS = jala.DnsClient.PKG.Question.TYPE_NS;
|
||||
|
||||
/**
|
||||
* The "PTR" record/query type.
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.DnsClient.TYPE_PTR = jala.DnsClient.PKG.Question.TYPE_PTR;
|
||||
|
||||
/**
|
||||
* The "SOA" record/query type.
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.DnsClient.TYPE_SOA = jala.DnsClient.PKG.Question.TYPE_SOA;
|
||||
|
||||
/**
|
||||
* The "TXT" record/query type.
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.DnsClient.TYPE_TXT = jala.DnsClient.PKG.Question.TYPE_TXT;
|
||||
|
||||
/**
|
||||
* The "WKS" record/query type.
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.DnsClient.TYPE_WKS = jala.DnsClient.PKG.Question.TYPE_WKS;
|
||||
|
||||
/**
|
||||
* Queries the nameserver for a specific domain
|
||||
* and the given type of record.
|
||||
* @param {String} dName The domain name to query for
|
||||
* @param {Number} queryType The type of records to retrieve
|
||||
* @returns The records retrieved from the nameserver
|
||||
* @type org.wonderly.net.dns.RR
|
||||
*/
|
||||
jala.DnsClient.prototype.query = function(dName, queryType) {
|
||||
if (dName == null) {
|
||||
throw new Error("no domain-name to query for");
|
||||
}
|
||||
if (queryType == null) {
|
||||
queryType = jala.DnsClient.TYPE_A;
|
||||
}
|
||||
// construct the question for querying the nameserver
|
||||
var question = new jala.DnsClient.PKG.Question(dName,
|
||||
queryType,
|
||||
jala.DnsClient.PKG.Question.CLASS_IN);
|
||||
// construct the query
|
||||
var query = new jala.DnsClient.PKG.Query(question);
|
||||
// run the query
|
||||
query.runQuery(this.nameServer);
|
||||
// wrap the records received in instances of jala.DnsClient.Record
|
||||
var answers = query.getAnswers();
|
||||
var arr = [];
|
||||
for (var i=0;i<answers.length;i++) {
|
||||
arr[i] = new jala.DnsClient.Record(answers[i]);
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convenience method to query for the MX-records
|
||||
* of the domain passed as argument.
|
||||
* @param {String} dName The domain name to query for
|
||||
* @returns The records retrieved from the nameserver
|
||||
* @type org.wonderly.net.dns.RR
|
||||
*/
|
||||
jala.DnsClient.prototype.queryMailHost = function (dName) {
|
||||
return this.query(dName, this.TYPE_MX);
|
||||
};
|
||||
|
||||
|
||||
/** @ignore */
|
||||
jala.DnsClient.toString = function() {
|
||||
return "[jala.DnsClient]";
|
||||
};
|
||||
|
||||
|
||||
/** @ignore */
|
||||
jala.DnsClient.prototype.toString = function() {
|
||||
return "[jala.DnsClient (" + this.nameServer + ")]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a new instance of jala.DnsClient.Record.
|
||||
* @class Instances of this class wrap record data as received
|
||||
* from the nameserver.
|
||||
* @param {org.wonderly.net.dns.RR} data The data as received from
|
||||
* the nameserver
|
||||
* @returns A newly constructed Record instance
|
||||
* @constructor
|
||||
*/
|
||||
jala.DnsClient.Record = function(data) {
|
||||
/**
|
||||
* The type of the nameserver record represented by this Answer instance.
|
||||
* @type Number
|
||||
* @see #TYPE_A
|
||||
* @see #TYPE_CNAME
|
||||
* @see #TYPE_HINFO
|
||||
* @see #TYPE_MX
|
||||
* @see #TYPE_NS
|
||||
* @see #TYPE_PTR
|
||||
* @see #TYPE_SOA
|
||||
* @see #TYPE_TXT
|
||||
* @see #TYPE_WKS
|
||||
*/
|
||||
this.type = data.getType();
|
||||
|
||||
/**
|
||||
* The name of the host. This will only be set for records
|
||||
* of type A, AAAA and NS.
|
||||
* @type String
|
||||
* @see #TYPE_A
|
||||
* @see #TYPE_AAAA
|
||||
* @see #TYPE_NS
|
||||
*/
|
||||
this.host = null;
|
||||
|
||||
/**
|
||||
* The IP address of the host. This will only be set for records
|
||||
* of type A and AAAA
|
||||
* @type String
|
||||
* @see #TYPE_A
|
||||
* @see #TYPE_AAAA
|
||||
*/
|
||||
this.ipAddress = null;
|
||||
|
||||
/**
|
||||
* The CNAME of this record. This will only be set for records
|
||||
* of type CNAME
|
||||
* @type String
|
||||
* @see #TYPE_CNAME
|
||||
*/
|
||||
this.cname = null;
|
||||
|
||||
/**
|
||||
* The name of the mail exchanging server. This is only set for
|
||||
* records of type MX
|
||||
* @type String
|
||||
* @see #TYPE_MX
|
||||
*/
|
||||
this.mx = null;
|
||||
|
||||
/**
|
||||
* The email address responsible for a name server. This property
|
||||
* will only be set for records of type SOA
|
||||
* @type String
|
||||
* @see #TYPE_SOA
|
||||
*/
|
||||
this.email = null;
|
||||
|
||||
/**
|
||||
* Descriptive text as received from the nameserver. This is only
|
||||
* set for records of type TXT
|
||||
* @type String
|
||||
* @see #TYPE_TXT
|
||||
*/
|
||||
this.text = null;
|
||||
|
||||
/**
|
||||
* Returns the wrapped nameserver record data
|
||||
* @returns The wrapped data
|
||||
* @type org.wonderly.net.dns.RR
|
||||
*/
|
||||
this.getData = function() {
|
||||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Main constructor body
|
||||
*/
|
||||
switch (data.getClass()) {
|
||||
case jala.DnsClient.PKG.ARR:
|
||||
case jala.DnsClient.PKG.AAAARR:
|
||||
this.host = data.getHost();
|
||||
this.ipAddress = data.getIPAddress();
|
||||
break;
|
||||
case jala.DnsClient.PKG.NSRR:
|
||||
this.host = data.getHost();
|
||||
break;
|
||||
case jala.DnsClient.PKG.CNAMERR:
|
||||
this.cname = data.getCName();
|
||||
break;
|
||||
case jala.DnsClient.PKG.MXRR:
|
||||
this.mx = data.getExchanger();
|
||||
break;
|
||||
case jala.DnsClient.PKG.SOARR:
|
||||
this.host = data.getNSHost();
|
||||
this.email = data.getResponsibleEmail();
|
||||
break;
|
||||
case jala.DnsClient.PKG.TXTRR:
|
||||
this.text = data.getText();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
jala.DnsClient.Record.prototype.toString = function() {
|
||||
return "[jala.DnsClient.Record]";
|
||||
};
|
2524
modules/jala/code/Form.js
Normal file
2524
modules/jala/code/Form.js
Normal file
File diff suppressed because it is too large
Load diff
130
modules/jala/code/Global.js
Normal file
130
modules/jala/code/Global.js
Normal file
|
@ -0,0 +1,130 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the Global prototype.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the value passed as argument is either a string literal,
|
||||
* an instance of String or of java.lang.String.
|
||||
* @param {Object} val The value to test
|
||||
* @returns True if the value is a string, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
function isString(val) {
|
||||
return typeof(val) == "string" ||
|
||||
val instanceof java.lang.String ||
|
||||
val instanceof String;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the value passed as argument is either a boolean
|
||||
* literal or an instance of Boolean.
|
||||
* @param {Object} val The value to test
|
||||
* @returns True if the value is a boolean, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
function isBoolean(val) {
|
||||
return typeof(val) == "boolean" ||
|
||||
val instanceof Boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the value passed as argument is either a number,
|
||||
* an instance of Number or of java.lang.Number.
|
||||
* @param {Object} val The value to test
|
||||
* @returns True if the value is a number, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
function isNumber(val) {
|
||||
return typeof(val) == "number" ||
|
||||
val instanceof java.lang.Number ||
|
||||
val instanceof Number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the value passed as argument is null.
|
||||
* @param {Object} val The value to test
|
||||
* @returns True if the value is null, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
function isNull(val) {
|
||||
return val === null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the value passed as argument is undefined.
|
||||
* @param {Object} val The value to test
|
||||
* @returns True if the value is undefined, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
function isUndefined(val) {
|
||||
return val === undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the value passed as argument is an array.
|
||||
* @param {Object} val The value to test
|
||||
* @returns True if the value is an array, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
function isArray(val) {
|
||||
return val instanceof Array;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the value passed as argument is either a Javascript date
|
||||
* or an instance of java.util.Date.
|
||||
* @param {Object} val The value to test
|
||||
* @returns True if the value is a date, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
function isDate(val) {
|
||||
return val instanceof Date ||
|
||||
val instanceof java.util.Date;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the value passed as argument is either a Javascript
|
||||
* object or an instance of java.lang.Object.
|
||||
* @param {Object} val The value to test
|
||||
* @returns True if the value is an object, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
function isObject(val) {
|
||||
return val instanceof Object ||
|
||||
val instanceof java.lang.Object;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the value passed as argument is a function.
|
||||
* @param {Object} val The value to test
|
||||
* @returns True if the argument is a function, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
function isFunction(val) {
|
||||
return val instanceof Function;
|
||||
};
|
253
modules/jala/code/History.js
Normal file
253
modules/jala/code/History.js
Normal file
|
@ -0,0 +1,253 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the jala.History class.
|
||||
*/
|
||||
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new History object.
|
||||
* @class This class is an implementation of a Browser-like history
|
||||
* stack suitable to use in any Helma application. The difference
|
||||
* to a Browser's history is that this implementation ignores
|
||||
* POST requests and checks if Urls in the stack are still valid to
|
||||
* prevent eg. redirections to a HopObject's url that has been deleted.
|
||||
* Plus it is capable to create new "intermediate" history-stacks
|
||||
* and this way maintain a "history of histories" which is needed for
|
||||
* eg. editing sessions in a popup window that should use their own
|
||||
* request history without interfering with the history of the
|
||||
* main window.
|
||||
* @constructor
|
||||
*/
|
||||
jala.History = function() {
|
||||
var MAX = 40;
|
||||
|
||||
/**
|
||||
* Stack constructor
|
||||
* @private
|
||||
*/
|
||||
var Stack = function(id) {
|
||||
this.items = [];
|
||||
this.id = id;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the current url including query string
|
||||
* @private
|
||||
*/
|
||||
var getUrl = function() {
|
||||
var query;
|
||||
var url = path.href(req.action);
|
||||
try {
|
||||
if (query = req.getServletRequest().getQueryString())
|
||||
url += "?" + query;
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a request is valid for being added
|
||||
* to the history stack. This method returns false
|
||||
* for all POST-requests or requests whose action name
|
||||
* contains a dot (to prevent requests for external stylesheets
|
||||
* or the like from being recorded).
|
||||
* @private
|
||||
* @type Boolean
|
||||
*/
|
||||
var isValid = function() {
|
||||
// FIXME: we should check for mimetype of response instead
|
||||
// of assuming that requests containing a dot aren't worth
|
||||
// being put into history stack ...
|
||||
if (req.isPost() || (req.action && req.action.contains(".")))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* returns a single Stack instance
|
||||
* @private
|
||||
*/
|
||||
var getStack = function() {
|
||||
if (history.length < 1)
|
||||
history.push(new Stack(getUrl()));
|
||||
return history[history.length -1];
|
||||
};
|
||||
|
||||
/**
|
||||
* Variable containing the history-stacks
|
||||
* @private
|
||||
*/
|
||||
var history = [];
|
||||
|
||||
/**
|
||||
* Initializes a new history stack, adds
|
||||
* it to the array of stacks (which makes it
|
||||
* the default one to use for further requests)
|
||||
* and records the current request Url.
|
||||
*/
|
||||
this.add = function() {
|
||||
if (!isValid())
|
||||
return;
|
||||
var url = getUrl();
|
||||
if (getStack().id != url) {
|
||||
history.push(new Stack(url));
|
||||
this.push();
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the current history stack
|
||||
*/
|
||||
this.remove = function() {
|
||||
history.pop();
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Records a request Url in the currently active
|
||||
* history stack.
|
||||
*/
|
||||
this.push = function() {
|
||||
if (isValid()) {
|
||||
var obj = path[path.length-1];
|
||||
var url = getUrl();
|
||||
var stack = getStack();
|
||||
if (stack.items.length < 1 || stack.items[stack.items.length -1].url != url) {
|
||||
if (stack.items.length >= MAX)
|
||||
stack.items.shift();
|
||||
stack.items.push({
|
||||
url: url,
|
||||
path: path.href().substring(root.href().length).replace(/\+/g, " ")
|
||||
});
|
||||
}
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the currently active history stack
|
||||
*/
|
||||
this.clear = function() {
|
||||
getStack().items.length = 0;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Redirects the client back to the first valid
|
||||
* request in history. Please mind that searching for
|
||||
* a valid Url starts at <em>history.length - 2</em>.
|
||||
* @param {Number} offset The index position in the stack to start
|
||||
* searching at
|
||||
*/
|
||||
this.redirect = function(offset) {
|
||||
res.redirect(this.pop(offset));
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the first valid request Url in history
|
||||
* stack starting with a given offset. The default offset is 1.
|
||||
* Any valid Url found is removed from the stack, therefor
|
||||
* this method <em>alters the contents of the history stack</em>.
|
||||
* @param {Number} offset The index position in history stack to start
|
||||
* searching at
|
||||
* @return The Url of the request
|
||||
* @type String
|
||||
*/
|
||||
this.pop = function(offset) {
|
||||
/**
|
||||
* checks if a referrer is stil valid
|
||||
* @private
|
||||
*/
|
||||
var isValidPath = function(p) {
|
||||
var arr = p.split("/");
|
||||
var obj = root;
|
||||
for (var i=0;i<arr.length -1;i++) {
|
||||
if (!(obj = obj.get(unescape(arr[i]))) || obj.__node__.getState() == 3)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var obj;
|
||||
var cut = offset != null ? offset : 1;
|
||||
var stack = getStack();
|
||||
if (stack.items.length > 0) {
|
||||
while (cut-- > 0) {
|
||||
obj = stack.items.pop();
|
||||
}
|
||||
}
|
||||
while (stack.items.length > 0) {
|
||||
obj = stack.items.pop();
|
||||
// check if url is valid
|
||||
if (isValidPath(obj.path)) {
|
||||
return obj.url;
|
||||
}
|
||||
}
|
||||
return path.href();
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the request Url at the given position
|
||||
* in the current history stack. If no offset is given
|
||||
* the last Url in the stack is returned. This method
|
||||
* <em>does not alter the stack contents</em>!
|
||||
* @param {Number} offset The index position in history stack to start
|
||||
* searching at
|
||||
* @return The Url of the request
|
||||
* @type String
|
||||
*/
|
||||
this.peek = function(offset) {
|
||||
var stack = getStack();
|
||||
return stack.items[stack.items.length - (offset != null ? offset : 1)];
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the contents of all history stacks
|
||||
* as string
|
||||
* @return The history stacks as string
|
||||
* @type String
|
||||
*/
|
||||
this.dump = function() {
|
||||
return history.toSource();
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
this.toString = function() {
|
||||
return "[History " + getStack().toSource() + "]";
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
177
modules/jala/code/HopObject.js
Normal file
177
modules/jala/code/HopObject.js
Normal file
|
@ -0,0 +1,177 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
/**
|
||||
* @fileoverview Additional fields and methods of the HopObject class.
|
||||
*/
|
||||
|
||||
/**
|
||||
* HelmaLib dependencies
|
||||
*/
|
||||
app.addRepository("modules/core/String.js");
|
||||
app.addRepository("modules/helma/File.js");
|
||||
|
||||
/**
|
||||
* Constructs a name from an object which
|
||||
* is unique in the underlying HopObject collection.
|
||||
* @param {Object} obj The object representing or containing
|
||||
* the alias name. Possible object types include:
|
||||
* <ul>
|
||||
* <li>File</li>
|
||||
* <li>helma.File</li>
|
||||
* <li>java.io.File</li>
|
||||
* <li>String</li>
|
||||
* <li>java.lang.String</li>
|
||||
* <li>Packages.helma.util.MimePart</li>
|
||||
* </ul>
|
||||
* @param {Number} maxLength The maximum length of the alias
|
||||
* @returns The resulting alias
|
||||
* @type String
|
||||
*/
|
||||
HopObject.prototype.getAccessName = function(obj, maxLength) {
|
||||
/**
|
||||
* Private method checking if the key passed as argument is already
|
||||
* existing in this object
|
||||
* @param {String} key The key string to test
|
||||
* @returns True in case the key is already in use, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
var isReserved = function(obj, key) {
|
||||
return key === "." ||
|
||||
key === ".." ||
|
||||
obj[key] != null ||
|
||||
obj[key + "_action"] != null ||
|
||||
obj.get(key) != null
|
||||
};
|
||||
|
||||
// prepare name depending on argument
|
||||
var name;
|
||||
var clazz = obj.constructor || obj.getClass();
|
||||
switch (clazz) {
|
||||
case File:
|
||||
case helma.File:
|
||||
case java.io.File:
|
||||
case Packages.helma.util.MimePart:
|
||||
// first fix bloody ie/win file paths containing backslashes
|
||||
name = obj.getName().split(/[\\\/]/).pop();
|
||||
if (name.contains("."))
|
||||
name = name.substring(0, name.lastIndexOf("."));
|
||||
break;
|
||||
case String:
|
||||
case java.lang.String:
|
||||
name = obj;
|
||||
break;
|
||||
default:
|
||||
name = obj.toString();
|
||||
}
|
||||
|
||||
// remove all (back)slashes
|
||||
var accessName = name.replace(/[\\\/]/g, "");
|
||||
// remove all plus signs
|
||||
accessName = accessName.replace("+","");
|
||||
if (accessName.length > maxLength) {
|
||||
accessName = accessName.substring(0, maxLength);
|
||||
}
|
||||
var result = accessName;
|
||||
if (isReserved(this, result)) {
|
||||
var len = result.length;
|
||||
var counter = 1;
|
||||
var overflow;
|
||||
while (isReserved(this, result)) {
|
||||
result = accessName + "-" + counter.toString();
|
||||
if ((overflow = result.length - maxLength) > 0) {
|
||||
result = accessName.substring(0, accessName.length - overflow) +
|
||||
"-" + counter.toString();
|
||||
if (result.length > maxLength) {
|
||||
throw "Unable to create accessname due to limit restriction";
|
||||
}
|
||||
}
|
||||
counter += 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the internal state of this HopObject is TRANSIENT.
|
||||
* @returns True if this HopObject is marked as <em>transient</em>, false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
HopObject.prototype.isTransient = function() {
|
||||
return this.__node__.getState() === Packages.helma.objectmodel.INodeState.TRANSIENT;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the internal state of this HopObject is VIRTUAL.
|
||||
* @returns True if this HopObject is marked as <em>virtual</em>, false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
HopObject.prototype.isVirtual = function() {
|
||||
return this.__node__.getState() === Packages.helma.objectmodel.INodeState.VIRTUAL;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the internal state of this HopObject is INVALID.
|
||||
* @returns True if this HopObject is marked as <em>invalid</em>, false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
HopObject.prototype.isInvalid = function() {
|
||||
return this.__node__.getState() === Packages.helma.objectmodel.INodeState.INVALID;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the internal state of this HopObject is CLEAN.
|
||||
* @returns True if this HopObject is marked as <em>clean</em>, false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
HopObject.prototype.isClean = function() {
|
||||
return this.__node__.getState() === Packages.helma.objectmodel.INodeState.CLEAN;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the internal state of this HopObject is NEW.
|
||||
* @returns True if this HopObject is marked as <em>new</em>, false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
HopObject.prototype.isNew = function() {
|
||||
return this.__node__.getState() === Packages.helma.objectmodel.INodeState.NEW;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the internal state of this HopObject is MODIFIED.
|
||||
* @returns True if this HopObject is marked as <em>modified</em>, false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
HopObject.prototype.isModified = function() {
|
||||
return this.__node__.getState() === Packages.helma.objectmodel.INodeState.MODIFIED;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the internal state of this HopObject is DELETED.
|
||||
* @returns True if this HopObject is marked as <em>deleted</em>, false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
HopObject.prototype.isDeleted = function() {
|
||||
return this.__node__.getState() === Packages.helma.objectmodel.INodeState.DELETED;
|
||||
};
|
156
modules/jala/code/HtmlDocument.js
Normal file
156
modules/jala/code/HtmlDocument.js
Normal file
|
@ -0,0 +1,156 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the jala.HtmlDocument class.
|
||||
*/
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Jala dependencies
|
||||
*/
|
||||
(function() {
|
||||
var jalaDir = getProperty("jala.dir", "modules/jala");
|
||||
app.addRepository(jalaDir + "/lib/dom4j-1.6.1.jar");
|
||||
app.addRepository(jalaDir + "/lib/jaxen-1.1-beta-8.jar");
|
||||
})();
|
||||
|
||||
/**
|
||||
* Construct a new HTML document.
|
||||
* @class This class provides easy access to the elements of
|
||||
* an arbitrary HTML document. By using TagSoup, Dom4J and Jaxen
|
||||
* even invalid HTML can be parsed, turned into an object tree
|
||||
* and easily be processed with XPath expressions.
|
||||
* @param {String} source The HTML source code.
|
||||
* @returns A new HTML document.
|
||||
* @constructor
|
||||
*/
|
||||
jala.HtmlDocument = function(source) {
|
||||
var REQUIREMENTS = {
|
||||
"dom4j-1.6.1": "http://www.dom4j.org",
|
||||
"jaxen-1.1-beta-8": "http://www.jaxen.org"
|
||||
};
|
||||
|
||||
var reader = new java.io.StringReader(source);
|
||||
var dom4j = Packages.org.dom4j;
|
||||
var tagsoup = "org.ccil.cowan.tagsoup.Parser";
|
||||
|
||||
try {
|
||||
var saxReader = new dom4j.io.SAXReader(tagsoup);
|
||||
var document = saxReader.read(reader);
|
||||
document.normalize();
|
||||
} catch(e) {
|
||||
res.push();
|
||||
res.write("\njala.HtmlDocument requires the following Java ");
|
||||
res.write("packages in ext/lib or application directory:\n");
|
||||
for (var i in REQUIREMENTS) {
|
||||
res.write(i);
|
||||
res.write(".jar");
|
||||
res.write(" [");
|
||||
res.write(REQUIREMENTS[i]);
|
||||
res.write("]\n");
|
||||
}
|
||||
throw (e + res.pop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all document nodes from an XPath expression.
|
||||
* @param {String} xpathExpr An XPath expression.
|
||||
* @returns A list of HTML elements.
|
||||
* @type org.dom4j.tree.DefaultElement
|
||||
*/
|
||||
this.scrape = function(xpathExpr) {
|
||||
return document.selectNodes(xpathExpr);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all link elements of the HTML document.
|
||||
* @returns A list of link elements.
|
||||
* @type Array
|
||||
*/
|
||||
this.getLinks = function() {
|
||||
var result = [];
|
||||
var list = this.scrape("//html:a");
|
||||
for (var i=0; i<list.size(); i+=1) {
|
||||
var element = list.get(i);
|
||||
var text = element.getText();
|
||||
var href = element.attribute("href");
|
||||
if (text && href) {
|
||||
result.push({
|
||||
text: text,
|
||||
url: href.getText()
|
||||
});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves all elements by name from the document.
|
||||
* The returned object structure is compatible for usage
|
||||
* in {@link jala.XmlWriter}.
|
||||
* @param {String} elementName The name of the desired element
|
||||
* @returns The list of available elements in the document
|
||||
* @type Array
|
||||
*/
|
||||
this.getAll = function(elementName) {
|
||||
var result = [], object;
|
||||
var list = this.scrape("//html:" + elementName);
|
||||
var i, n, element, text, attributes, attr, size;
|
||||
for (i=0; i<list.size(); i+=1) {
|
||||
element = list.get(i);
|
||||
object = {
|
||||
name: element.getName(),
|
||||
value: element.getText() || null
|
||||
};
|
||||
attributes = element.attributes();
|
||||
if ((size = attributes.size()) > 0) {
|
||||
object.attributes = new Array;
|
||||
for (n=0; n<size; n+=1) {
|
||||
attr = attributes.get(n);
|
||||
object.attributes.push({
|
||||
name: attr.getName(),
|
||||
value: attr.getData() || null
|
||||
});
|
||||
}
|
||||
}
|
||||
result.push(object);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a string representation of the HTML document.
|
||||
* @returns A string representation of the HTML document.
|
||||
* @type String
|
||||
*/
|
||||
this.toString = function() {
|
||||
return "[jala.HtmlDocument " + source.length + " Bytes]";
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
403
modules/jala/code/I18n.js
Normal file
403
modules/jala/code/I18n.js
Normal file
|
@ -0,0 +1,403 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
/**
|
||||
* @fileoverview Methods and macros for internationalization
|
||||
* of Helma applications.
|
||||
*/
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of jala.I18n
|
||||
* @class This class provides various functions and macros for
|
||||
* internationalization of Helma applications.
|
||||
* @constructor
|
||||
* @type jala.I18n
|
||||
*/
|
||||
jala.I18n = function() {
|
||||
/**
|
||||
* The default object containing the messages.
|
||||
* @ignore
|
||||
*/
|
||||
var messages = global.messages;
|
||||
|
||||
/**
|
||||
* The default method for retrieving the locale.
|
||||
* @ignore
|
||||
*/
|
||||
var localeGetter = function() {
|
||||
return java.util.Locale.getDefault();
|
||||
};
|
||||
|
||||
/**
|
||||
* Overwrite the default object containing
|
||||
* the messages (ie. a vanilla EcmaScript object).
|
||||
* @param {Object} msgObject The object containing the messages
|
||||
*/
|
||||
this.setMessages = function(msgObject) {
|
||||
messages = msgObject;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the message object.
|
||||
* @returns The object containing the messages
|
||||
* @type Object
|
||||
*/
|
||||
this.getMessages = function() {
|
||||
return messages;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the method for retrieving the locale.
|
||||
* @param {Function} func The getter method
|
||||
*/
|
||||
this.setLocaleGetter = function(func) {
|
||||
if (func && func.constructor == Function) {
|
||||
localeGetter = func;
|
||||
} else {
|
||||
throw Error("Getter method to retrieve locale must be a function");
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the method for retrieving the locale.
|
||||
* @returns The getter method
|
||||
* @type Function
|
||||
*/
|
||||
this.getLocaleGetter = function() {
|
||||
return localeGetter;
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* The default handler containing the messages.
|
||||
* @ignore
|
||||
*/
|
||||
jala.I18n.HANDLER = global;
|
||||
|
||||
/** @ignore */
|
||||
jala.I18n.prototype.toString = function() {
|
||||
return "[Jala i18n]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Set (overwrite) the default handler containing
|
||||
* the messages (ie. a vanilla EcmaScript object).
|
||||
* @param {Object} handler The handler containing the message object
|
||||
* @deprecated Use {@link #setMessages} instead
|
||||
*/
|
||||
jala.I18n.prototype.setHandler = function(handler) {
|
||||
this.setMessages(handler.messages);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the locale for the given id, which is expected to follow
|
||||
* the form <code>language[_COUNTRY][_variant]</code>, where <code>language</code>
|
||||
* is a valid ISO Language Code (eg. "de"), <code>COUNTRY</code> a valid ISO
|
||||
* Country Code (eg. "AT"), and variant an identifier for the variant to use.
|
||||
* @returns The locale for the given id
|
||||
* @type java.util.Locale
|
||||
*/
|
||||
jala.I18n.prototype.getLocale = function(localeId) {
|
||||
if (localeId) {
|
||||
if (localeId.indexOf("_") > -1) {
|
||||
var arr = localeId.split("_");
|
||||
if (arr.length == 3) {
|
||||
return new java.util.Locale(arr[0], arr[1], arr[2]);
|
||||
} else {
|
||||
return new java.util.Locale(arr[0], arr[1]);
|
||||
}
|
||||
} else {
|
||||
return new java.util.Locale(localeId);
|
||||
}
|
||||
}
|
||||
return java.util.Locale.getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to "translate" the given message key into a localized
|
||||
* message.
|
||||
* @param {String} key The message to translate (required)
|
||||
* @param {String} plural The plural form of the message to translate
|
||||
* @param {Number} amount A number to determine whether to use the
|
||||
* singular or plural form of the message
|
||||
* @returns The localized message or the appropriate key if no
|
||||
* localized message was found
|
||||
* @type String
|
||||
*/
|
||||
jala.I18n.prototype.translate = function(singularKey, pluralKey, amount) {
|
||||
var translation = null;
|
||||
if (singularKey) {
|
||||
// use the getter method for retrieving the locale
|
||||
var locale = this.getLocaleGetter()();
|
||||
var catalog, key;
|
||||
if ((catalog = jala.i18n.getCatalog(locale))) {
|
||||
if (arguments.length == 3 && amount != 1) { // is plural
|
||||
key = pluralKey;
|
||||
} else {
|
||||
key = singularKey;
|
||||
}
|
||||
if (!(translation = catalog[key])) {
|
||||
translation = key;
|
||||
app.logger.debug("jala.i18n.translate(): Can't find message '" +
|
||||
key + "' for locale '" + locale + "'");
|
||||
}
|
||||
} else {
|
||||
app.logger.debug("jala.i18n.translate(): Can't find message catalog for locale '" + locale + "'");
|
||||
if (!pluralKey || amount == 1) {
|
||||
translation = singularKey;
|
||||
} else {
|
||||
translation = pluralKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
return translation;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper method to get the message catalog
|
||||
* corresponding to the actual locale.
|
||||
* @params {java.util.Locale} locale
|
||||
* @returns The message catalog.
|
||||
*/
|
||||
jala.I18n.prototype.getCatalog = function(locale) {
|
||||
if (!jala.I18n.catalogs) {
|
||||
jala.I18n.catalogs = {};
|
||||
}
|
||||
|
||||
var catalog = jala.I18n.catalogs[locale];
|
||||
|
||||
if (catalog) return catalog;
|
||||
|
||||
var messages = this.getMessages();
|
||||
|
||||
if (locale && messages) {
|
||||
catalog = messages[locale.toLanguageTag()];
|
||||
jala.I18n.catalogs[locale] = catalog;
|
||||
}
|
||||
|
||||
return catalog;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts the message passed as argument into an instance
|
||||
* of java.text.MessageFormat, and formats it using the
|
||||
* replacement values passed.
|
||||
* @param {String} message The message to format
|
||||
* @param {Array} values An optional array containing replacement values
|
||||
* @returns The formatted message or, if the formatting fails, the
|
||||
* message passed as argument.
|
||||
* @type String
|
||||
* @see http://java.sun.com/j2se/1.5.0/docs/api/java/text/MessageFormat.html
|
||||
*/
|
||||
jala.I18n.prototype.formatMessage = function(message, values) {
|
||||
if (message) {
|
||||
var args = null;
|
||||
if (values != null && values.length > 0) {
|
||||
args = java.lang.reflect.Array.newInstance(java.lang.Object, values.length);
|
||||
var arg;
|
||||
for (var i=0;i<values.length;i++) {
|
||||
if ((arg = values[i]) != null) {
|
||||
// MessageFormat can't deal with javascript date objects
|
||||
// so we need to convert them into java.util.Date instances
|
||||
if (arg instanceof Date) {
|
||||
args[i] = new java.util.Date(arg.getTime());
|
||||
} else {
|
||||
args[i] = arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// use the getter method for retrieving the locale
|
||||
var locale = this.getLocaleGetter()();
|
||||
// format the message
|
||||
try {
|
||||
var msgFormat = new java.text.MessageFormat(message, locale);
|
||||
return msgFormat.format(args);
|
||||
} catch (e) {
|
||||
app.logger.warn("jala.i18n.formatMessage(): Unable to format message '"
|
||||
+ message + "', reason: " + e, e.javaException);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a localized message for the message key passed as
|
||||
* argument. If no localization is found, the message key
|
||||
* is returned. Any additional arguments passed to this function
|
||||
* will be used as replacement values during message rendering.
|
||||
* To reference these values the message can contain placeholders
|
||||
* following "{number}" notation, where <code>number</code> must
|
||||
* match the number of the additional argument (starting with zero).
|
||||
* @param {String} key The message to localize
|
||||
* @returns The translated message
|
||||
* @type String
|
||||
* @see #translate
|
||||
* @see #formatMessage
|
||||
*/
|
||||
jala.I18n.prototype.gettext = function(key /** [value 0][, value 1][, ...] */) {
|
||||
return this.formatMessage(this.translate(key),
|
||||
Array.prototype.splice.call(arguments, 1));
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a localized message for the message key passed as
|
||||
* argument. In contrast to gettext() this method
|
||||
* can handle plural forms based on the amount passed as argument.
|
||||
* If no localization is found, the appropriate message key is
|
||||
* returned. Any additional arguments passed to this function
|
||||
* will be used as replacement values during message rendering.
|
||||
* To reference these values the message can contain placeholders
|
||||
* following "{number}" notation, where <code>number</code> must
|
||||
* match the number of the additional argument (starting with zero).
|
||||
* @param {String} singularKey The singular message to localize
|
||||
* @param {String} pluralKey The plural form of the message to localize
|
||||
* @param {Number} amount The amount which is used to determine
|
||||
* whether the singular or plural form of the message should be returned.
|
||||
* @returns The translated message
|
||||
* @type String
|
||||
* @see #translate
|
||||
* @see #formatMessage
|
||||
*/
|
||||
jala.I18n.prototype.ngettext = function(singularKey, pluralKey, amount /** [value 0][, value 1][, ...] */) {
|
||||
return this.formatMessage(this.translate(singularKey, pluralKey, amount || 0),
|
||||
Array.prototype.splice.call(arguments, 2));
|
||||
};
|
||||
|
||||
/**
|
||||
* A simple proxy method which is used to mark a message string
|
||||
* for the i18n parser as to be translated.
|
||||
* @param {String} key The message that should be seen by the
|
||||
* i18n parser as to be translated.
|
||||
* @returns The message in unmodified form
|
||||
* @type String
|
||||
*/
|
||||
jala.I18n.prototype.markgettext = function(key) {
|
||||
return key;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a translated message. The following macro attributes
|
||||
* are accepted:
|
||||
* <ul>
|
||||
* <li>text: The message to translate (required)</li>
|
||||
* <li>plural: The plural form of the message</li>
|
||||
* <li>values: A list of replacement values. Use a comma to separate more
|
||||
* than one value. Each value is either interpreted as a global property
|
||||
* (if it doesn't containg a dot) or as a property name of the given macro
|
||||
* handler object (eg. "user.name"). If the value of the property is a
|
||||
* HopObject or an Array this macro uses the size() resp. length of the
|
||||
* object, otherwise the string representation of the object will be used.</li>
|
||||
* </ul>
|
||||
* @returns The translated message
|
||||
* @type String
|
||||
* @see #gettext
|
||||
* @see #ngettext
|
||||
*/
|
||||
jala.I18n.prototype.message_macro = function(param) {
|
||||
if (param.text) {
|
||||
var args = [param.text];
|
||||
if (param.plural) {
|
||||
args[args.length] = param.plural;
|
||||
}
|
||||
if (param.values != null) {
|
||||
var arr = param.values.split(/\s*,\s*/g);
|
||||
// convert replacement values: if the value name doesn't contain
|
||||
// a dot, look for a global property with that name, otherwise
|
||||
// for a property of the specified macro handler object.
|
||||
var propName, dotIdx, handlerName, handler;
|
||||
for (var i=0;i<arr.length;i++) {
|
||||
if ((propName = arr[i]) != null) {
|
||||
var value = null;
|
||||
if ((dotIdx = propName.indexOf(".")) > 0) {
|
||||
var handlerName = propName.substring(0, dotIdx);
|
||||
if (handlerName == "request") {
|
||||
handler = req.data;
|
||||
} else if (handlerName == "response") {
|
||||
handler = res.data;
|
||||
} else if (!(handler = res.handlers[handlerName])) {
|
||||
continue;
|
||||
}
|
||||
propName = propName.substring(dotIdx + 1);
|
||||
// primitive security: don't allow access to internal properties
|
||||
// and a property named "password"
|
||||
if (propName.charAt(0) != "_" && propName.toLowerCase() != "password") {
|
||||
value = handler[propName];
|
||||
}
|
||||
} else {
|
||||
value = global[propName];
|
||||
}
|
||||
if (value != null) {
|
||||
// if its a HopObject collection or Array, use its size/length
|
||||
// as value
|
||||
if (value instanceof HopObject) {
|
||||
value = value.size();
|
||||
} else if (value instanceof Array) {
|
||||
value = value.length;
|
||||
}
|
||||
}
|
||||
args[args.length] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (param.plural) {
|
||||
return this.ngettext.apply(this, args);
|
||||
} else {
|
||||
return this.gettext.apply(this, args);
|
||||
}
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default i18n class instance.
|
||||
* @type jala.I18n
|
||||
* @final
|
||||
*/
|
||||
jala.i18n = new jala.I18n();
|
||||
|
||||
/**
|
||||
* For convenience reasons the public methods and macros are
|
||||
* put into global scope too
|
||||
*/
|
||||
var gettext = function() {
|
||||
return jala.i18n.gettext.apply(jala.i18n, arguments);
|
||||
};
|
||||
var ngettext = function() {
|
||||
return jala.i18n.ngettext.apply(jala.i18n, arguments);
|
||||
};
|
||||
var markgettext = function() {
|
||||
return jala.i18n.markgettext.apply(jala.i18n, arguments);
|
||||
};
|
||||
var message_macro = function() {
|
||||
return jala.i18n.message_macro.apply(jala.i18n, arguments);
|
||||
};
|
362
modules/jala/code/ImageFilter.js
Normal file
362
modules/jala/code/ImageFilter.js
Normal file
|
@ -0,0 +1,362 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the jala.ImageFilter class.
|
||||
*/
|
||||
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new ImageFilter object
|
||||
* @class This class provides several image manipulating
|
||||
* methods. Most of this filter library is based on filters created
|
||||
* by Janne Kipinä for JAlbum. For more information have a look
|
||||
* at http://www.ratol.fi/~jakipina/java/
|
||||
* @param {Object} img Either
|
||||
<ul>
|
||||
<li>an instance of helma.image.ImageWrapper</li>
|
||||
<li>the path to the image file as String</li>
|
||||
<li>an instance of helma.File representing the image file</li>
|
||||
<li>an instance of java.io.File representing the image file</li>
|
||||
</ul>
|
||||
* @constructor
|
||||
*/
|
||||
jala.ImageFilter = function(img) {
|
||||
/**
|
||||
* The buffered image to work on
|
||||
* @type java.awt.image.BufferedImage
|
||||
* @private
|
||||
*/
|
||||
var bi;
|
||||
|
||||
/**
|
||||
* Perfoms a gaussian operation (unsharp masking or blurring)
|
||||
* on the image using the kernelFactory passed as argument
|
||||
* @param {Number} radius The radius
|
||||
* @param {Number} amount The amount
|
||||
* @param {Function} kernelFactory Factory method to call for building the kernel
|
||||
* @private
|
||||
*/
|
||||
var gaussianOp = function(radius, amount, kernelFactory) {
|
||||
var DEFAULT_RADIUS = 2;
|
||||
var MINIMUM_RADIUS = 1;
|
||||
var MAXIMUM_RADIUS = 10;
|
||||
var DEFAULT_AMOUNT = 15;
|
||||
var MINIMUM_AMOUNT = 1;
|
||||
var MAXIMUM_AMOUNT = 100;
|
||||
|
||||
// correct arguments if necessary
|
||||
if (isNaN(radius = Math.min(Math.max(radius, MINIMUM_RADIUS), MAXIMUM_RADIUS)))
|
||||
radius = DEFAULT_RADIUS;
|
||||
if (isNaN(amount = Math.min(Math.max(amount, MINIMUM_AMOUNT), MAXIMUM_AMOUNT)))
|
||||
amount = DEFAULT_AMOUNT;
|
||||
|
||||
if ((bi.getWidth() < bi.getHeight()) && (radius > bi.getWidth())) {
|
||||
radius = bi.getWidth();
|
||||
} else if ((bi.getHeight() < bi.getWidth()) && (radius > bi.getHeight())) {
|
||||
radius = bi.getHeight();
|
||||
}
|
||||
|
||||
var size = (radius * 2) + 1;
|
||||
var deviation = amount / 20;
|
||||
var elements = kernelFactory(size, deviation);
|
||||
var large = jala.ImageFilter.getEnlargedImageWithMirroring(bi, radius);
|
||||
var resultImg = new java.awt.image.BufferedImage(large.getWidth(), large.getHeight(), large.getType());
|
||||
var kernel = new java.awt.image.Kernel(size, size, elements);
|
||||
var cop = new java.awt.image.ConvolveOp(kernel, java.awt.image.ConvolveOp.EDGE_NO_OP, null);
|
||||
cop.filter(large, resultImg);
|
||||
// replace the wrapped buffered image with the modified one
|
||||
bi = resultImg.getSubimage(radius, radius, bi.getWidth(), bi.getHeight());
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sharpens the image using a plain sharpening kernel.
|
||||
* @param {Number} amount The amount of sharpening to apply
|
||||
*/
|
||||
this.sharpen = function(amount) {
|
||||
var DEFAULT = 20;
|
||||
var MINIMUM = 1;
|
||||
var MAXIMUM = 100;
|
||||
// correct argument if necessary
|
||||
if (isNaN(Math.min(Math.max(amount, MINIMUM), MAXIMUM)))
|
||||
amount = DEFAULT;
|
||||
var sharpened = new java.awt.image.BufferedImage(bi.getWidth(), bi.getHeight(), bi.getType());
|
||||
var kernel = new java.awt.image.Kernel(3, 3, jala.ImageFilter.getSharpeningKernel(amount));
|
||||
var cop = new java.awt.image.ConvolveOp(kernel, java.awt.image.ConvolveOp.EDGE_NO_OP, null);
|
||||
cop.filter(bi, sharpened);
|
||||
bi = sharpened;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs an unsharp mask operation on the image
|
||||
* @param {Number} radius The radius
|
||||
* @param {Number} amount The amount
|
||||
*/
|
||||
this.unsharpMask = function(radius, amount) {
|
||||
gaussianOp(radius, amount, jala.ImageFilter.getUnsharpMaskKernel);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs a gaussian blur operation on the image
|
||||
* @param {Number} radius The radius
|
||||
* @param {Number} amount The amount
|
||||
*/
|
||||
this.gaussianBlur = function(radius, amount) {
|
||||
gaussianOp(radius, amount, jala.ImageFilter.getGaussianBlurKernel);
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the image that has been worked on
|
||||
* @return An instance of helma.image.ImageWrapper
|
||||
* @type helma.image.ImageWrapper
|
||||
*/
|
||||
this.getImage = function() {
|
||||
var generator = Packages.helma.image.ImageGenerator.getInstance();
|
||||
return new Packages.helma.image.ImageWrapper(bi,
|
||||
bi.getWidth(),
|
||||
bi.getHeight(),
|
||||
generator);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the wrapped image as byte array, to use eg. in conjunction
|
||||
* with res.writeBinary()
|
||||
* @returns The wrapped image as byte array
|
||||
* @type byte[]
|
||||
*/
|
||||
this.getBytes = function() {
|
||||
var outStream = new java.io.ByteArrayOutputStream();
|
||||
Packages.javax.imageio.ImageIO.write(bi, "jpeg", outStream);
|
||||
var bytes = outStream.toByteArray();
|
||||
outStream.close();
|
||||
return bytes;
|
||||
};
|
||||
|
||||
/**
|
||||
* constructor body
|
||||
* @ignore
|
||||
*/
|
||||
if (arguments.length == 0 || img == null) {
|
||||
throw "jala.ImageFilter: insufficient arguments";
|
||||
} else if (img instanceof Packages.helma.image.ImageWrapper) {
|
||||
bi = img.getBufferedImage();
|
||||
} else {
|
||||
if (typeof(img) == "string") {
|
||||
var inStream = new java.io.FileInputStream(new java.io.File(img));
|
||||
} else {
|
||||
var inStream = new java.io.FileInputStream(img);
|
||||
}
|
||||
var decoder = Packages.com.sun.image.codec.jpeg.JPEGCodec.createJPEGDecoder(inStream);
|
||||
bi = decoder.decodeAsBufferedImage();
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
jala.ImageFilter.prototype.toString = function() {
|
||||
return "[jala.ImageFilter]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Transforms an image into a bigger one while mirroring the edges
|
||||
* This method is used to apply the filtering up to the edges
|
||||
* of an image (otherwise the image would keep an unmodified
|
||||
* border).
|
||||
* @param {java.awt.image.BufferedImage} bi The buffered image to transform
|
||||
* @param {Number} size The size of the border area
|
||||
* @returns The transformed image
|
||||
* @type java.awt.image.BufferedImage
|
||||
* @private
|
||||
*/
|
||||
jala.ImageFilter.getEnlargedImageWithMirroring = function(bi, size) {
|
||||
|
||||
var doFlip = function(bi, sx, sy, dist) {
|
||||
var out = new java.awt.image.BufferedImage(bi.getWidth(), bi.getHeight(), bi.getType());
|
||||
var transform = java.awt.geom.AffineTransform.getScaleInstance(sx, sy);
|
||||
(sx < sy) ? transform.translate(-dist, 0) : transform.translate(0, -dist);
|
||||
var atop = new java.awt.image.AffineTransformOp(transform,
|
||||
java.awt.image.AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
|
||||
out = atop["filter(java.awt.image.BufferedImage,java.awt.image.BufferedImage)"](bi, null);
|
||||
return out;
|
||||
}
|
||||
|
||||
var doHorizontalFlip = function(bi) {
|
||||
return doFlip(bi, -1, 1, bi.getWidth());
|
||||
}
|
||||
|
||||
var doVerticalFlip = function(bi) {
|
||||
return doFlip(bi, 1, -1, bi.getHeight());
|
||||
}
|
||||
|
||||
var width = bi.getWidth() + 2 * size;
|
||||
var height = bi.getHeight() + 2 * size;
|
||||
var out = new java.awt.image.BufferedImage(width, height, bi.getType());
|
||||
var g = out.createGraphics();
|
||||
// due to method overloading exactly define the method to be called
|
||||
var func = "drawImage(java.awt.Image,int,int,java.awt.image.ImageObserver)";
|
||||
g[func](bi, size, size, null);
|
||||
|
||||
var part;
|
||||
//top-left corner
|
||||
part = bi.getSubimage(0, 0, size, size);
|
||||
part = doHorizontalFlip(part);
|
||||
part = doVerticalFlip(part);
|
||||
g[func](part, 0, 0, null);
|
||||
//top-right corner
|
||||
part = bi.getSubimage(bi.getWidth()-size, 0, size, size);
|
||||
part = doHorizontalFlip(part);
|
||||
part = doVerticalFlip(part);
|
||||
g[func](part, width-size, 0, null);
|
||||
//bottom-left corner
|
||||
part = bi.getSubimage(0, bi.getHeight()-size, size, size);
|
||||
part = doHorizontalFlip(part);
|
||||
part = doVerticalFlip(part);
|
||||
g[func](part, 0, height-size, null);
|
||||
//bottom-right corner
|
||||
part = bi.getSubimage(bi.getWidth()-size, bi.getHeight()-size, size, size);
|
||||
part = doHorizontalFlip(part);
|
||||
part = doVerticalFlip(part);
|
||||
g[func](part, width-size, height-size, null);
|
||||
//left border
|
||||
part = bi.getSubimage(0, 0, size, bi.getHeight());
|
||||
part = doHorizontalFlip(part);
|
||||
g[func](part, 0, size, null);
|
||||
//right border
|
||||
part = bi.getSubimage(bi.getWidth()-size, 0, size, bi.getHeight());
|
||||
part = doHorizontalFlip(part);
|
||||
g[func](part, width-size, size, null);
|
||||
//top border
|
||||
part = bi.getSubimage(0, 0, bi.getWidth(), size);
|
||||
part = doVerticalFlip(part);
|
||||
g[func](part, size, 0, null);
|
||||
//bottom border
|
||||
part = bi.getSubimage(0, bi.getHeight()-size, bi.getWidth(), size);
|
||||
part = doVerticalFlip(part);
|
||||
g[func](part, size, height-size, null);
|
||||
return out;
|
||||
};
|
||||
|
||||
/**
|
||||
* Factory method for a gaussian blur kernel
|
||||
* @returns The gaussian blur kernel
|
||||
* @param {Number} size The size of the kernel
|
||||
* @param {Number} deviation The deviation to use
|
||||
* @returns The gaussian blur kernel
|
||||
* @type float[]
|
||||
* @private
|
||||
*/
|
||||
jala.ImageFilter.getGaussianBlurKernel = function(size, deviation) {
|
||||
var nominator = 2 * deviation * deviation;
|
||||
var kernel = java.lang.reflect.Array.newInstance(java.lang.Float.TYPE, size*size);
|
||||
var center = (size - 1) / 2;
|
||||
var limit = size - 1;
|
||||
var xx, yy;
|
||||
var sum = 0;
|
||||
var value = 0;
|
||||
for (var y=0; y<size; y++) {
|
||||
for (var x=0; x<size; x++) {
|
||||
if ((y <= center) && (x <= center)) {
|
||||
if (x >= y) {
|
||||
//calculate new value
|
||||
xx = center - x;
|
||||
yy = center - y;
|
||||
value = Math.exp(-(xx*xx + yy*yy) / nominator);
|
||||
kernel[(y*size)+x] = value;
|
||||
sum += value;
|
||||
} else {
|
||||
//copy existing value
|
||||
value = kernel[(x*size)+y];
|
||||
kernel[(y*size)+x] = value;
|
||||
sum += value;
|
||||
}
|
||||
} else {
|
||||
xx = x;
|
||||
yy = y;
|
||||
if (yy > center)
|
||||
yy = limit - yy;
|
||||
if (xx > center)
|
||||
xx = limit - xx;
|
||||
value = kernel[(yy*size)+xx];
|
||||
kernel[(y*size)+x] = value;
|
||||
sum += value;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i=0; i<kernel.length; i++) {
|
||||
kernel[i] = kernel[i] / sum;
|
||||
}
|
||||
return kernel;
|
||||
};
|
||||
|
||||
/**
|
||||
* Factory method for an unsharp mask kernel
|
||||
* @param {Number} size The size of the kernel
|
||||
* @param {Number} deviation The deviation to use
|
||||
* @returns The unsharp mask kernel
|
||||
* @type float[]
|
||||
* @private
|
||||
*/
|
||||
jala.ImageFilter.getUnsharpMaskKernel = function(size, deviation) {
|
||||
var elements = jala.ImageFilter.getGaussianBlurKernel(size, deviation);
|
||||
var center = ((size * size) - 1) / 2;
|
||||
elements[center] = 0;
|
||||
var sum = 0;
|
||||
for (var i=0; i<elements.length; i++) {
|
||||
sum += elements[i];
|
||||
elements[i] = -elements[i];
|
||||
}
|
||||
elements[center] = sum + 1;
|
||||
return elements;
|
||||
};
|
||||
|
||||
/**
|
||||
* Factory method for a sharpening kernel
|
||||
* @param {Number} amount The amount of sharpening to use
|
||||
* @return The sharpening kernel
|
||||
* @type float[]
|
||||
* @private
|
||||
*/
|
||||
jala.ImageFilter.getSharpeningKernel = function(amount) {
|
||||
var kernel = java.lang.reflect.Array.newInstance(java.lang.Float.TYPE, 9);
|
||||
var corner = 0;
|
||||
var side = amount / -50;
|
||||
var center = (side * -4.0) + (corner * -4.0) + 1.0;
|
||||
kernel[0] = kernel[2] = kernel[6] = kernel[8] = corner;
|
||||
kernel[1] = kernel[3] = kernel[5] = kernel[7] = side;
|
||||
kernel[4] = center;
|
||||
return kernel;
|
||||
};
|
||||
|
765
modules/jala/code/IndexManager.js
Normal file
765
modules/jala/code/IndexManager.js
Normal file
|
@ -0,0 +1,765 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the jala.IndexManager class.
|
||||
*/
|
||||
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* HelmaLib dependencies
|
||||
*/
|
||||
app.addRepository("modules/helma/Search.js");
|
||||
app.addRepository("modules/helma/File.js");
|
||||
|
||||
/**
|
||||
* Constructs a new IndexManager object.
|
||||
* @class This class basically sits on top of a helma.Search.Index instance
|
||||
* and provides methods for adding, removing and optimizing the underlying index.
|
||||
* All methods generate jobs that are put into an internal queue which is
|
||||
* processed asynchronously by a separate worker thread. This means all calls
|
||||
* to add(), remove() and optimize() will return immediately, but the changes to
|
||||
* the index will be done within a short delay. Please keep in mind to change the
|
||||
* status of this IndexManager instance to REBUILDING before starting to rebuild
|
||||
* the index, as this ensures that all add/remove/optimize jobs will stay in the
|
||||
* queue and will only be processed after switching the status back to NORMAL.
|
||||
* This ensures that objects that have been modified during a rebuilding process
|
||||
* are re-indexed properly afterwards.
|
||||
* @param {String} name The name of the index, which is the name of the directory
|
||||
* the index already resides or will be created in.
|
||||
* @param {helma.File} dir The base directory where this index's directory
|
||||
* is already existing or will be created in. If not specified a RAM directory
|
||||
* is used.
|
||||
* @param {String} lang The language of the documents in this index. This leads
|
||||
* to the proper Lucene analyzer being used for indexing documents.
|
||||
* @constructor
|
||||
* @see helma.Search.createIndex
|
||||
*/
|
||||
jala.IndexManager = function IndexManager(name, dir, lang) {
|
||||
|
||||
/**
|
||||
* Private variable containing the worker thread
|
||||
* @private
|
||||
*/
|
||||
var thread = null;
|
||||
|
||||
/**
|
||||
* Private flag indicating that the worker thread should stop
|
||||
* @type Boolean
|
||||
* @private
|
||||
*/
|
||||
var interrupted = false;
|
||||
|
||||
/**
|
||||
* Private variable containing the index managed by
|
||||
* this IndexManager instance.
|
||||
* @private
|
||||
*/
|
||||
var index = null;
|
||||
|
||||
/**
|
||||
* Private variable containing a status indicator.
|
||||
* @type Number
|
||||
* @private
|
||||
*/
|
||||
var status = jala.IndexManager.NORMAL;
|
||||
|
||||
/**
|
||||
* Synchronized linked list that functions as a queue for
|
||||
* asynchronous processing of index manipulation jobs.
|
||||
* @type java.util.LinkedList
|
||||
* @private
|
||||
* @see jala.IndexManager.Job
|
||||
*/
|
||||
var queue = java.util.Collections.synchronizedList(new java.util.LinkedList());
|
||||
|
||||
/**
|
||||
* The name of the unique identifier field in the index. Defaults to "id".
|
||||
* @type String
|
||||
* @private
|
||||
*/
|
||||
var idFieldname = "id";
|
||||
|
||||
/**
|
||||
* The index directory
|
||||
* @type Packages.org.apache.lucene.store.Directory
|
||||
* @private
|
||||
*/
|
||||
var indexDirectory = null;
|
||||
|
||||
/**
|
||||
* The searcher utilized by {@link #search}
|
||||
* @type jala.IndexManager.Searcher
|
||||
* @private
|
||||
*/
|
||||
var searcher = null;
|
||||
|
||||
/**
|
||||
* Returns the directory of the underlying index
|
||||
* @returns The directory of the underlying index
|
||||
* @type Packages.org.apache.lucene.store.Directory
|
||||
*/
|
||||
this.getDirectory = function() {
|
||||
return indexDirectory;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the underlying index.
|
||||
* @returns The index this queue is working on.
|
||||
* @type helma.Search.Index
|
||||
*/
|
||||
this.getIndex = function() {
|
||||
return index;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the status of this manager.
|
||||
* @returns The status of this index manager.
|
||||
* @type Number
|
||||
* @see #NORMAL
|
||||
* @see #REBUILDING
|
||||
*/
|
||||
this.getStatus = function() {
|
||||
return status;
|
||||
};
|
||||
|
||||
/**
|
||||
* Modifies the status of this manager, which has implications
|
||||
* on how index modifying jobs are handled. If the status
|
||||
* is {@link #REBUILDING}, all jobs are queued until the status
|
||||
* is set back to {@link #NORMAL}.
|
||||
* @param {Number} s The new status of this manager.
|
||||
* @see #NORMAL
|
||||
* @see #REBUILDING
|
||||
*/
|
||||
this.setStatus = function(s) {
|
||||
status = s;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the queue this index manager is using.
|
||||
* @returns The queue.
|
||||
* @type java.util.LinkedList
|
||||
*/
|
||||
this.getQueue = function() {
|
||||
return queue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the name of the index manger, which
|
||||
* is equal to the name of the underlying index
|
||||
* @returns The name of the index manager
|
||||
* @type String
|
||||
*/
|
||||
this.getName = function() {
|
||||
return name;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the name of the field containing the unique identifier
|
||||
* of document objects in the index wrapped by this IndexManager.
|
||||
* Defaults to "id".
|
||||
* @returns The name of the id field in the index
|
||||
* @type String
|
||||
* @see #setIdFieldname
|
||||
*/
|
||||
this.getIdFieldname = function() {
|
||||
return idFieldname;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the name of the field containing the unique identifier
|
||||
* of document objects in the index wrapped by this IndexManager.
|
||||
* @see #getIdFieldname
|
||||
*/
|
||||
this.setIdFieldname = function(name) {
|
||||
idFieldname = name;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the underlying index is currently optimized.
|
||||
* @returns True in case the index is optimized, false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
this.hasOptimizingJob = function() {
|
||||
for (var i=0; i<queue.size(); i++) {
|
||||
if (queue.get(i).type == jala.IndexManager.Job.OPTIMIZE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the underlying index is currently rebuilding.
|
||||
* @returns True in case the index is rebuilding, false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
this.isRebuilding = function() {
|
||||
return status == jala.IndexManager.REBUILDING;
|
||||
};
|
||||
|
||||
/**
|
||||
* Starts the IndexManager worker thread that processes the job queue
|
||||
*/
|
||||
this.start = function() {
|
||||
if (!this.isRunning()) {
|
||||
interrupted = false;
|
||||
thread = app.invokeAsync(this, function() {
|
||||
while (interrupted === false) {
|
||||
if (this.getStatus() != jala.IndexManager.REBUILDING && !queue.isEmpty()) {
|
||||
var job = queue.remove(0);
|
||||
if (this.processJob(job) === false) {
|
||||
// processing job failed, check if we should re-add
|
||||
if (job.errors < jala.IndexManager.MAXTRIES) {
|
||||
// increment error counter and put back into queue
|
||||
job.errors += 1;
|
||||
queue.add(job);
|
||||
} else {
|
||||
this.log("error", "error during queue flush: tried " +
|
||||
jala.IndexManager.MAXTRIES + " times to handle " +
|
||||
job.type + " job " + ", giving up.");
|
||||
}
|
||||
}
|
||||
this.log("debug", "remaining jobs " + queue.size());
|
||||
// if no more jobs are waiting, optimize the index and re-open
|
||||
// the index searcher to make changes visible
|
||||
if (queue.isEmpty()) {
|
||||
var start = java.lang.System.currentTimeMillis();
|
||||
try {
|
||||
this.getIndex().optimize();
|
||||
this.log("optimized index in " + jala.IndexManager.getRuntime(start) + " ms");
|
||||
this.initSearcher();
|
||||
} catch (e) {
|
||||
this.log("error", "Unable to optimize index or re-open searcher, reason: " + e.toString());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// wait for 100ms before checking again
|
||||
java.lang.Thread.sleep(100);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, [], -1);
|
||||
this.log("started successfully");
|
||||
} else {
|
||||
this.log("already running");
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stops this IndexManager instance. This function waits for 10 seconds
|
||||
* maximum for the worker thread to stop.
|
||||
* @returns True if the worker thread stopped successfully, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
this.stop = function() {
|
||||
interrupted = true;
|
||||
var result;
|
||||
if ((result = this.isRunning()) === true) {
|
||||
if ((result = thread.waitForResult(10000)) === true) {
|
||||
thread = null;
|
||||
this.log("stopped successfully");
|
||||
} else {
|
||||
result = false;
|
||||
this.log("error", "unable to stop");
|
||||
}
|
||||
} else {
|
||||
this.log("info", "already stopped");
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if this IndexManager instance is running
|
||||
* @returns True if this IndexManager instance is running, false otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
this.isRunning = function() {
|
||||
if (thread != null) {
|
||||
return thread.running;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read only reference containing the running status of this IndexManager
|
||||
* @type Boolean
|
||||
*/
|
||||
this.running; // for api documentation only, is overwritten by getter below
|
||||
this.__defineGetter__("running", function() {
|
||||
return this.isRunning()
|
||||
});
|
||||
|
||||
/**
|
||||
* Read only reference containing the number of pending jobs
|
||||
* @type Number
|
||||
*/
|
||||
this.pending; // for api documentation only, is overwritten by getter below
|
||||
this.__defineGetter__("pending", function() {
|
||||
return queue.size()
|
||||
});
|
||||
|
||||
/**
|
||||
* Initializes the searcher
|
||||
* @private
|
||||
*/
|
||||
this.initSearcher = function() {
|
||||
searcher = new Packages.org.apache.lucene.search.IndexSearcher(indexDirectory);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the searcher of this index manager
|
||||
* @returns The searcher of this index manager
|
||||
* @type org.apache.lucene.search.IndexSearcher
|
||||
* @private
|
||||
*/
|
||||
this.getSearcher = function() {
|
||||
if (searcher === null) {
|
||||
this.initSearcher();
|
||||
}
|
||||
return searcher;
|
||||
};
|
||||
|
||||
/**
|
||||
* Main constructor body. Initializes the underlying index.
|
||||
*/
|
||||
var search = new helma.Search();
|
||||
var analyzer = helma.Search.getAnalyzer(lang);
|
||||
if (dir != null) {
|
||||
indexDirectory = search.getDirectory(new helma.File(dir, name));
|
||||
this.log("created/mounted " + indexDirectory);
|
||||
} else {
|
||||
indexDirectory = search.getRAMDirectory();
|
||||
this.log("created new RAM directory");
|
||||
}
|
||||
index = search.createIndex(indexDirectory, analyzer);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Constant defining the maximum number of tries to add/remove
|
||||
* an object to/from the underlying index.
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.IndexManager.MAXTRIES = 10;
|
||||
|
||||
/**
|
||||
* Constant defining normal mode of this index manager.
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.IndexManager.NORMAL = 1;
|
||||
|
||||
/**
|
||||
* Constant defining rebuilding mode of this index manager.
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.IndexManager.REBUILDING = 2;
|
||||
|
||||
/**
|
||||
* Returns the milliseconds elapsed between the current timestamp
|
||||
* and the one passed as argument.
|
||||
* @returns The elapsed time in millis.
|
||||
* @type Number
|
||||
* @private
|
||||
*/
|
||||
jala.IndexManager.getRuntime = function(millis) {
|
||||
return java.lang.System.currentTimeMillis() - millis;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
jala.IndexManager.prototype.toString = function() {
|
||||
return "[" + this.constructor.name + " '" + this.getName() + "' (" +
|
||||
this.pending + " objects queued)]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function that prefixes every log message with
|
||||
* the name of the IndexManager.
|
||||
* @param {String} level An optional logging level. Accepted values
|
||||
* @param {String} msg The log message
|
||||
* are "debug", "info", "warn" and "error".
|
||||
*/
|
||||
jala.IndexManager.prototype.log = function(/* msg, level */) {
|
||||
var level = "info", message;
|
||||
if (arguments.length == 2) {
|
||||
level = arguments[0];
|
||||
message = arguments[1];
|
||||
} else {
|
||||
message = arguments[0];
|
||||
}
|
||||
app.logger[level]("[" + this.constructor.name + " '" +
|
||||
this.getName() + "'] " + message);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Static helper method that returns the value of the "id"
|
||||
* field of a document object.
|
||||
* @param {helma.Search.Document} doc The document whose id
|
||||
* should be returned.
|
||||
* @private
|
||||
*/
|
||||
jala.IndexManager.prototype.getDocumentId = function(doc) {
|
||||
try {
|
||||
return doc.getField(this.getIdFieldname()).value;
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Queues the document object passed as argument for addition to the underlying
|
||||
* index. This includes that all existing documents with the same identifier will
|
||||
* be removed before the object passed as argument is added.
|
||||
* @param {helma.Search.Document} doc The document object that should be
|
||||
* added to the underlying index.
|
||||
* @returns True if the job was added successfully to the internal queue,
|
||||
* false otherwise.
|
||||
* @type Boolean
|
||||
* @see helma.Search.Document
|
||||
*/
|
||||
jala.IndexManager.prototype.add = function(doc) {
|
||||
var id;
|
||||
if (!doc) {
|
||||
this.log("error", "missing document object to add");
|
||||
return false;
|
||||
} else if ((id = this.getDocumentId(doc)) == null) {
|
||||
this.log("error", "document doesn't contain an Id field '" +
|
||||
this.getIdFieldname() + "'");
|
||||
return false;
|
||||
}
|
||||
// the job's callback function which actually adds the document to the index
|
||||
var callback = function() {
|
||||
var start = java.lang.System.currentTimeMillis();
|
||||
this.getIndex().updateDocument(doc, this.getIdFieldname());
|
||||
this.log("debug", "added document with Id " + id +
|
||||
" to index in " + jala.IndexManager.getRuntime(start) + " ms");
|
||||
return;
|
||||
}
|
||||
var job = new jala.IndexManager.Job(jala.IndexManager.Job.ADD, callback);
|
||||
this.getQueue().add(job);
|
||||
this.log("debug", "queued adding document " + id + " to index");
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Queues the removal of all index documents whose identifier value ("id" by default)
|
||||
* matches the number passed as argument.
|
||||
* @param {Number} id The identifier value
|
||||
* @returns True if the removal job was added successfully to the queue, false
|
||||
* otherwise.
|
||||
* @type Boolean
|
||||
*/
|
||||
jala.IndexManager.prototype.remove = function(id) {
|
||||
if (id === null || isNaN(id)) {
|
||||
this.log("error", "missing or invalid document id to remove");
|
||||
return false;
|
||||
}
|
||||
// the job's callback function which actually removes all documents
|
||||
// with the given id from the index
|
||||
var callback = function() {
|
||||
var start = java.lang.System.currentTimeMillis();
|
||||
this.getIndex().removeDocument(this.getIdFieldname(), parseInt(id, 10));
|
||||
this.log("debug", "removed document with Id " + id +
|
||||
" from index in " + jala.IndexManager.getRuntime(start) + " ms");
|
||||
};
|
||||
var job = new jala.IndexManager.Job(jala.IndexManager.Job.REMOVE, callback);
|
||||
this.getQueue().add(job);
|
||||
this.log("debug", "queued removal of document with Id " + id);
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Queues the optimization of the underlying index. Normally there is no need
|
||||
* to call this method explicitly, as the index will be optimized after all
|
||||
* queued jobs have been processed.
|
||||
* @returns True if the optimizing job was added, false otherwise, which means
|
||||
* that there is already an optimizing job waiting in the queue.
|
||||
* @type Boolean
|
||||
*/
|
||||
jala.IndexManager.prototype.optimize = function() {
|
||||
if (this.hasOptimizingJob()) {
|
||||
return false;
|
||||
}
|
||||
var callback = function() {
|
||||
var start = java.lang.System.currentTimeMillis();
|
||||
this.getIndex().optimize();
|
||||
this.log("optimized index in " + jala.IndexManager.getRuntime(start) + " ms");
|
||||
// re-open index searcher, so that changes are seen
|
||||
this.initSearcher();
|
||||
return;
|
||||
};
|
||||
var job = new jala.IndexManager.Job(jala.IndexManager.Job.OPTIMIZE, callback);
|
||||
this.getQueue().add(job);
|
||||
this.log("debug", "queued index optimization");
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Processes a single queued job
|
||||
* @param {Object} job
|
||||
* @private
|
||||
*/
|
||||
jala.IndexManager.prototype.processJob = function(job) {
|
||||
this.log("debug", job.type + " job has been in queue for " +
|
||||
jala.IndexManager.getRuntime(job.createtime.getTime()) +
|
||||
" ms, processing now...");
|
||||
try {
|
||||
job.callback.call(this);
|
||||
} catch (e) {
|
||||
this.log("error", "Exception while processing job " + job.type + ": " + e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Searches the underlying index using the searcher of this index manager
|
||||
* @param {helma.Search.Query|org.apache.lucene.search.Query} query The query
|
||||
* to execute. Can be either an instance of helma.Search.Query, or an instance
|
||||
* of org.apache.lucene.search.Query
|
||||
* @param {helma.Search.QueryFilter|org.apache.lucene.search.Filter} filter
|
||||
* An optional query filter
|
||||
* @param {Array} sortFields An optional array containing
|
||||
* org.apache.lucene.search.SortField instances to use for sorting the result
|
||||
* @returns A HitCollection containing the search results
|
||||
* @type helma.Search.HitCollection
|
||||
*/
|
||||
jala.IndexManager.prototype.search = function(query, filter, sortFields) {
|
||||
var pkg = Packages.org.apache.lucene;
|
||||
if (query == null || (!(query instanceof helma.Search.Query) &&
|
||||
!(query instanceof pkg.search.Query))) {
|
||||
throw "jala.IndexManager search(): missing or invalid query";
|
||||
} else if (query instanceof helma.Search.Query) {
|
||||
// unwrap query
|
||||
query = query.getQuery();
|
||||
}
|
||||
if (filter != null && filter instanceof helma.Search.QueryFilter) {
|
||||
// unwrap filter
|
||||
filter = filter.getFilter();
|
||||
}
|
||||
|
||||
var searcher = this.getSearcher();
|
||||
var analyzer = this.getIndex().getAnalyzer();
|
||||
var hits;
|
||||
if (sortFields != null && sortFields.length > 0) {
|
||||
// convert the array with sortfields to a java array
|
||||
var arr = java.lang.reflect.Array.newInstance(pkg.search.SortField, sortFields.length);
|
||||
sortFields.forEach(function(sortField, idx) {
|
||||
arr[idx] = sortField;
|
||||
});
|
||||
var sort = pkg.search.Sort(arr);
|
||||
if (filter) {
|
||||
hits = searcher.search(query, filter, sort);
|
||||
} else {
|
||||
hits = searcher.search(query, sort);
|
||||
}
|
||||
} else if (filter) {
|
||||
hits = searcher.search(query, filter);
|
||||
} else {
|
||||
hits = searcher.search(query);
|
||||
}
|
||||
this.log("debug", "Query: " + query.toString());
|
||||
return new helma.Search.HitCollection(hits);
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses the query string passed as argument into a lucene Query instance
|
||||
* @param {String} queryStr The query string to parse
|
||||
* @param {Array} fields An array containing the names of the files to search in
|
||||
* @param {Object} boostMap An optional object containing properties whose name denotes
|
||||
* the name of the field to boost in the query, and the value the boost value.
|
||||
* @returns The query
|
||||
* @type org.apache.lucene.search.Query
|
||||
*/
|
||||
jala.IndexManager.prototype.parseQuery = function(queryStr, fields, boostMap) {
|
||||
if (queryStr == null || typeof(queryStr) !== "string") {
|
||||
throw "IndexManager.parseQuery(): missing or invalid query string";
|
||||
}
|
||||
if (fields == null || fields.constructor !== Array || fields.length < 1) {
|
||||
throw "IndexManager.parseQuery(): missing fields argument";
|
||||
}
|
||||
var query = null;
|
||||
var analyzer = this.getIndex().getAnalyzer();
|
||||
var pkg = Packages.org.apache.lucene;
|
||||
var map = null;
|
||||
if (boostMap != null) {
|
||||
// convert the javascript object into a HashMap
|
||||
map = new java.util.HashMap();
|
||||
for (var name in boostMap) {
|
||||
map.put(name, new java.lang.Float(boostMap[name]));
|
||||
}
|
||||
}
|
||||
var parser;
|
||||
try {
|
||||
if (fields.length > 1) {
|
||||
parser = new pkg.queryParser.MultiFieldQueryParser(fields, analyzer, map);
|
||||
} else {
|
||||
parser = new pkg.queryParser.QueryParser(fields, analyzer);
|
||||
}
|
||||
query = parser.parse(queryStr);
|
||||
} catch (e) {
|
||||
// ignore, but write a message to debug log
|
||||
app.logger.debug("Unable to construct search query '" + queryStr +
|
||||
"', reason: " + e);
|
||||
}
|
||||
return query;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses the query passed as argument and returns a caching filter. If an array
|
||||
* with more than one query strings is passed as argument, this method constructs
|
||||
* a boolean query filter where all queries in the array must match.
|
||||
* @param {String|Array} query Either a query string, or an array containing
|
||||
* one or more query strings
|
||||
* @param {org.apache.lucene.analysis.Analyzer} analyzer Optional analyzer
|
||||
* to use when parsing the filter query
|
||||
* @returns A caching query filter
|
||||
* @type org.apache.lucene.search.CachingWrapperFilter
|
||||
*/
|
||||
jala.IndexManager.prototype.parseQueryFilter = function(query, analyzer) {
|
||||
var filter = null;
|
||||
if (query != null) {
|
||||
var pkg = Packages.org.apache.lucene;
|
||||
// use the index' analyzer if none has been specified
|
||||
if (analyzer == null) {
|
||||
analyzer = this.getIndex().getAnalyzer();
|
||||
}
|
||||
var parser = new pkg.queryParser.QueryParser("", analyzer);
|
||||
var filterQuery;
|
||||
try {
|
||||
if (query.constructor === Array) {
|
||||
if (query.length > 1) {
|
||||
filterQuery = new pkg.search.BooleanQuery();
|
||||
query.forEach(function(queryStr){
|
||||
filterQuery.add(parser.parse(queryStr), pkg.search.BooleanClause.Occur.MUST);
|
||||
}, this);
|
||||
} else {
|
||||
filterQuery = parser.parse(query[0]);
|
||||
}
|
||||
} else {
|
||||
filterQuery = parser.parse(query);
|
||||
}
|
||||
filter = new pkg.search.CachingWrapperFilter(new pkg.search.QueryWrapperFilter(filterQuery));
|
||||
} catch (e) {
|
||||
app.logger.debug("Unable to parse query filter '" + query + "', reason: " + e);
|
||||
}
|
||||
}
|
||||
return filter;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*********************
|
||||
***** J O B *****
|
||||
*********************/
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new Job instance.
|
||||
* @class Instances of this class represent a single index
|
||||
* manipulation job to be processed by the index manager.
|
||||
* @param {Number} id The Id of the job
|
||||
* @param {Number} type The type of job, which can be either
|
||||
* jala.IndexManager.Job.ADD, jala.IndexManager.Job.REMOVE
|
||||
* or jala.IndexManager.Job.OPTIMIZE.
|
||||
* @param {Object} data The data needed to process the job.
|
||||
* @returns A newly created Job instance.
|
||||
* @constructor
|
||||
* @see jala.IndexManager.Job
|
||||
*/
|
||||
jala.IndexManager.Job = function(type, callback) {
|
||||
/**
|
||||
* The type of the job
|
||||
* @type Number
|
||||
*/
|
||||
this.type = type;
|
||||
|
||||
/**
|
||||
* The data needed to process this job. For adding jobs this property
|
||||
* must contain the {@link helma.Search.Document} instance to add to
|
||||
* the index. For removal job this property must contain the unique identifier
|
||||
* of the document that should be removed from the index. For optimizing
|
||||
* jobs this property is null.
|
||||
*/
|
||||
this.callback = callback;
|
||||
|
||||
/**
|
||||
* An internal error counter which is increased whenever processing
|
||||
* the job failed.
|
||||
* @type Number
|
||||
* @see jala.IndexManager.MAXTRIES
|
||||
*/
|
||||
this.errors = 0;
|
||||
|
||||
/**
|
||||
* The date and time at which this job was created.
|
||||
* @type Date
|
||||
*/
|
||||
this.createtime = new Date();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
jala.IndexManager.Job.prototype.toString = function() {
|
||||
return "[Job (type: " + this.type + ")]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Constant defining an add job
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.IndexManager.Job.ADD = "add";
|
||||
|
||||
/**
|
||||
* Constant defining a removal job
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.IndexManager.Job.REMOVE = "remove";
|
||||
|
||||
/**
|
||||
* Constant defining an optimizing job
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.IndexManager.Job.OPTIMIZE = "optimize";
|
1130
modules/jala/code/ListRenderer.js
Normal file
1130
modules/jala/code/ListRenderer.js
Normal file
File diff suppressed because it is too large
Load diff
1521
modules/jala/code/Mp3.js
Normal file
1521
modules/jala/code/Mp3.js
Normal file
File diff suppressed because it is too large
Load diff
129
modules/jala/code/PodcastWriter.js
Normal file
129
modules/jala/code/PodcastWriter.js
Normal file
|
@ -0,0 +1,129 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the jala.PodcastWriter class.
|
||||
*/
|
||||
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Jala dependencies
|
||||
*/
|
||||
app.addRepository(getProperty("jala.dir", "modules/jala") +
|
||||
"/code/Rss20Writer.js");
|
||||
|
||||
/**
|
||||
* @class Class to create, modify and render standard-compliant
|
||||
* RSS 2.0 feeds including support for Apple's Podcast specification.
|
||||
* @constructor
|
||||
* @extends jala.Rss20Writer
|
||||
* @param {String} header Optional XML header.
|
||||
*/
|
||||
jala.PodcastWriter = function(header) {
|
||||
jala.Rss20Writer.apply(this, arguments);
|
||||
|
||||
var CATEGORY = {
|
||||
name: "itunes:category",
|
||||
attributes: {
|
||||
name: "text"
|
||||
}
|
||||
};
|
||||
|
||||
var OWNER = {
|
||||
name: "itunes:owner",
|
||||
value: [{
|
||||
name: "itunes:name"
|
||||
}, {
|
||||
name: "itunes:email"
|
||||
}]
|
||||
};
|
||||
|
||||
this.addNamespace("itunes", "http://www.itunes.com/dtds/podcast-1.0.dtd");
|
||||
|
||||
this.extendChannel([{
|
||||
name: "itunes:author"
|
||||
}, {
|
||||
name: "itunes:subtitle"
|
||||
}, {
|
||||
name: "itunes:summary"
|
||||
}, {
|
||||
name: "itunes:new-feed-url"
|
||||
}, {
|
||||
name: "itunes:image",
|
||||
attributes: [{
|
||||
name: "href"
|
||||
}]
|
||||
}, {
|
||||
name: "itunes:link",
|
||||
attributes: [{
|
||||
name: "rel"
|
||||
}, {
|
||||
name: "type"
|
||||
}, {
|
||||
name: "href"
|
||||
}]
|
||||
}]);
|
||||
|
||||
this.getChannel().setValue(this.createElement(OWNER));
|
||||
|
||||
this.extendItem([{
|
||||
name: "itunes:duration"
|
||||
}, {
|
||||
name: "itunes:subtitle"
|
||||
}]);
|
||||
|
||||
/**
|
||||
* Add an iTunes Podcast category.
|
||||
* @param {String} name The category's name.
|
||||
* @param {String} subName The (optional) sub-category's name.
|
||||
* @param {jala.XmlWriter.XmlElement} parent Optional parent
|
||||
* element to add the category to.
|
||||
*/
|
||||
this.addItunesCategory = function(name, subName, parent) {
|
||||
if (!parent)
|
||||
parent = this.getChannel();
|
||||
var cat = this.createElement(CATEGORY);
|
||||
cat.populate({attributes: {text: name}});
|
||||
if (subName) {
|
||||
var subCat = this.createElement(CATEGORY);
|
||||
subCat.populate({attributes: {text: subName}});
|
||||
cat.addValue(subCat);
|
||||
}
|
||||
parent.addValue(cat);
|
||||
return;
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/** A typical XML header as default.
|
||||
@type String @final */
|
||||
jala.PodcastWriter.XMLHEADER = '<?xml version="1.0" encoding="UTF-8"?>';
|
307
modules/jala/code/RemoteContent.js
Normal file
307
modules/jala/code/RemoteContent.js
Normal file
|
@ -0,0 +1,307 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the jala.RemoteContent class.
|
||||
*/
|
||||
|
||||
// HelmaLib dependencies
|
||||
app.addRepository("modules/core/String.js");
|
||||
app.addRepository("modules/core/Object.js");
|
||||
app.addRepository("modules/core/Date.js");
|
||||
app.addRepository("modules/helma/Http.js");
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new remote content handler.
|
||||
* @class API to define, fetch and update content
|
||||
* from a remote site.
|
||||
* @param {String} url The URL string of the remote site.
|
||||
* @param {Integer} method The method to retrieve the remote content.
|
||||
* @param {File} storage The cache directory.
|
||||
* @returns A new remote content handler.
|
||||
* @extends helma.Http
|
||||
* @constructor
|
||||
*/
|
||||
jala.RemoteContent = function(url, method, storage) {
|
||||
if (typeof PropertyMgr == "undefined")
|
||||
var PropertyMgr = {};
|
||||
|
||||
var NULLSTR = "";
|
||||
var key = url.md5();
|
||||
var fname = key + jala.RemoteContent.SUFFIX;
|
||||
var cache;
|
||||
method = (method != null ? method.toLowerCase() : null);
|
||||
|
||||
// depending on the method argument the instance
|
||||
// becomes extent of the appropriate remote client
|
||||
switch (method) {
|
||||
case jala.RemoteContent.XMLRPC:
|
||||
break;
|
||||
default:
|
||||
helma.Http.call(this);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!storage) {
|
||||
storage = jala.RemoteContent.CACHEDIR;
|
||||
if (!storage.exists() || !storage.isDirectory())
|
||||
storage.mkdir(storage.getAbsolutePath());
|
||||
}
|
||||
|
||||
var getCache = function() {
|
||||
switch (storage.constructor) {
|
||||
case HopObject:
|
||||
cache = storage;
|
||||
break;
|
||||
|
||||
case PropertyMgr:
|
||||
cache = storage.getAll();
|
||||
break;
|
||||
|
||||
default:
|
||||
var f = new File(storage, fname);
|
||||
cache = f.exists() ? Xml.read(f) : new HopObject();
|
||||
}
|
||||
return cache;
|
||||
};
|
||||
|
||||
var setCache = function() {
|
||||
cache.url = url;
|
||||
cache.method = method;
|
||||
if (!cache.interval) {
|
||||
cache.interval = Date.ONEHOUR;
|
||||
}
|
||||
cache.lastUpdate = new Date();
|
||||
cache = cache.clone(new HopObject());
|
||||
|
||||
switch (storage.constructor) {
|
||||
case HopObject:
|
||||
for (var i in cache)
|
||||
storage[i] = cache[i];
|
||||
break;
|
||||
|
||||
case PropertyMgr:
|
||||
storage.setAll(cache);
|
||||
break;
|
||||
|
||||
default:
|
||||
var f = new File(storage, fname);
|
||||
Xml.write(cache, f);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
cache = getCache();
|
||||
|
||||
/**
|
||||
* Set the interval the remote content's
|
||||
* cache is bound to be updated.
|
||||
* @param {Number} interval The interval value in milliseconds.
|
||||
*/
|
||||
this.setInterval = function(interval) {
|
||||
cache.interval = parseInt(interval, 10);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an arbitrary property of the remote content.
|
||||
* @param {String} key The name of the property.
|
||||
* @returns The value of the property.
|
||||
*/
|
||||
this.get = function(key) {
|
||||
return cache[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available property names.
|
||||
* @returns The list of property names.
|
||||
* @type Array
|
||||
*/
|
||||
this.getKeys = function() {
|
||||
var keys = [];
|
||||
for (var i in cache) {
|
||||
keys.push(i);
|
||||
}
|
||||
return keys.sort();
|
||||
};
|
||||
|
||||
/**
|
||||
* Tests whether the remote content needs to be updated.
|
||||
* @returns True if the remote content needs to be updated.
|
||||
* @type Boolean
|
||||
*/
|
||||
this.needsUpdate = function() {
|
||||
if (!cache.lastUpdate) {
|
||||
return true;
|
||||
} else {
|
||||
var max = new Date() - cache.interval;
|
||||
if (max - cache.lastUpdate > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the updated and cached remote content.
|
||||
* @returns The content as retrieved from the remote site.
|
||||
* @type String
|
||||
*/
|
||||
this.update = function() {
|
||||
app.debug("[jala.RemoteContent] Retrieving " + url);
|
||||
var result;
|
||||
switch (method) {
|
||||
case jala.RemoteContent.XMLRPC:
|
||||
break;
|
||||
default:
|
||||
result = this.getUrl(url, cache.lastModified || cache.eTag);
|
||||
if (result.code != 200 && cache.content) {
|
||||
// preserve the content received before
|
||||
result.content = cache.content;
|
||||
}
|
||||
result.interval = cache.interval;
|
||||
cache = result;
|
||||
}
|
||||
setCache();
|
||||
return cache.content;
|
||||
};
|
||||
|
||||
/**
|
||||
* Flushes (empties) the cached remote content.
|
||||
*/
|
||||
this.clear = function() {
|
||||
switch (storage.constructor) {
|
||||
case HopObject:
|
||||
for (var i in storage)
|
||||
delete storage[i];
|
||||
break;
|
||||
|
||||
case PropertyMgr:
|
||||
storage.reset();
|
||||
break;
|
||||
|
||||
default:
|
||||
var f = new File(storage, fname);
|
||||
f.remove();
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a string representation of the remote content.
|
||||
* @returns The remote content as string.
|
||||
* @type String
|
||||
*/
|
||||
this.toString = function() {
|
||||
return cache.content || NULLSTR;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the value of the remote content.
|
||||
* @returns The remote content including response header data.
|
||||
* @type Object
|
||||
*/
|
||||
this.valueOf = function() {
|
||||
return cache;
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* A constant representing the HTTP retrieval method.
|
||||
* @type int
|
||||
* @final
|
||||
*/
|
||||
jala.RemoteContent.HTTP = 1;
|
||||
|
||||
/**
|
||||
* A constant representing the XML-RPC retrieval method.
|
||||
* @type int
|
||||
* @final
|
||||
*/
|
||||
jala.RemoteContent.XMLRPC = 2;
|
||||
|
||||
/**
|
||||
* The default name of the cache directory.
|
||||
* @type String
|
||||
* @final
|
||||
*/
|
||||
jala.RemoteContent.SUFFIX = ".cache";
|
||||
|
||||
/**
|
||||
* The default cache directory.
|
||||
* @type File
|
||||
* @final
|
||||
*/
|
||||
jala.RemoteContent.CACHEDIR = new File(app.dir, jala.RemoteContent.SUFFIX);
|
||||
|
||||
/**
|
||||
* Remove all remote content from a file-based cache.
|
||||
* @param {File} cache An optional target directory.
|
||||
*/
|
||||
jala.RemoteContent.flush = function(cache) {
|
||||
jala.RemoteContent.forEach(function(rc) {
|
||||
rc.clear();
|
||||
return;
|
||||
});
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply a custom method on all remote content in a file-based cache.
|
||||
* @param {Function} callback The callback method to be executed
|
||||
* for each remote content file.
|
||||
* @param {File} cache An optional target directory.
|
||||
*/
|
||||
jala.RemoteContent.forEach = function(callback, cache) {
|
||||
if (!cache)
|
||||
cache = jala.RemoteContent.CACHEDIR;
|
||||
var f, rc;
|
||||
var files = cache.list();
|
||||
for (var i in files) {
|
||||
f = new File(cache, files[i]);
|
||||
if (!files[i].endsWith(jala.RemoteContent.SUFFIX))
|
||||
continue;
|
||||
rc = new jala.RemoteContent(Xml.read(f).url);
|
||||
if (callback && callback.constructor == Function)
|
||||
callback(rc);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply a custom method on all remote content in a file-based cache.
|
||||
* @param {Function} callback The callback method to be executed
|
||||
* for each remote content file.
|
||||
* @param {File} cache An optional target directory.
|
||||
* @deprecated Use {@link #forEach} instead.
|
||||
*/
|
||||
jala.RemoteContent.exec = function() {
|
||||
jala.RemoteContent.forEach.apply(this, arguments);
|
||||
};
|
334
modules/jala/code/Rss20Writer.js
Normal file
334
modules/jala/code/Rss20Writer.js
Normal file
|
@ -0,0 +1,334 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the jala.Rss20Writer class.
|
||||
*/
|
||||
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Jala dependencies
|
||||
*/
|
||||
app.addRepository(getProperty("jala.dir", "modules/jala") +
|
||||
"/code/XmlWriter.js");
|
||||
|
||||
/**
|
||||
* @class Class to create, modify and render standard-compliant
|
||||
* RSS 2.0 feeds.
|
||||
* @constructor
|
||||
* @extends jala.XmlWriter
|
||||
* @param {String} header Optional XML header.
|
||||
*/
|
||||
jala.Rss20Writer = function(header) {
|
||||
// defines the prototype of this constructor
|
||||
jala.XmlWriter.apply(this, arguments);
|
||||
|
||||
// this should do the same but alas, helma throws
|
||||
// an error the very first time it is executed:
|
||||
//arguments.callee.prototype = new jala.XmlWriterInterface();
|
||||
|
||||
var DATEFMT = "EEE, dd MMM yyyy HH:mm:ss Z";
|
||||
|
||||
var CATEGORY = {
|
||||
name: "category",
|
||||
amount: Infinity,
|
||||
attributes: {
|
||||
name: "domain",
|
||||
}
|
||||
};
|
||||
|
||||
var ITEM = {
|
||||
name: "item",
|
||||
amount: Infinity,
|
||||
value: [{
|
||||
name: "title",
|
||||
required: true
|
||||
}, {
|
||||
name: "link",
|
||||
}, {
|
||||
name: "description",
|
||||
}, {
|
||||
name: "author",
|
||||
}, {
|
||||
name: "comments",
|
||||
}, {
|
||||
name: "enclosure",
|
||||
attributes: [{
|
||||
name: "url",
|
||||
required: true
|
||||
}, {
|
||||
name: "length",
|
||||
required: true
|
||||
}, {
|
||||
name: "type",
|
||||
required: true
|
||||
}]
|
||||
}, {
|
||||
name: "guid",
|
||||
attributes: [{
|
||||
name: "isPermaLink",
|
||||
type: Boolean
|
||||
}]
|
||||
}, {
|
||||
name: "pubDate",
|
||||
type: Date,
|
||||
format: DATEFMT
|
||||
}, {
|
||||
name: "source",
|
||||
attributes: [{
|
||||
name: "url",
|
||||
required: true
|
||||
}]
|
||||
}]
|
||||
};
|
||||
|
||||
var CHANNEL = {
|
||||
name: "channel",
|
||||
value: [{
|
||||
name: "title",
|
||||
required: true
|
||||
}, {
|
||||
name: "link",
|
||||
required: true
|
||||
}, {
|
||||
name: "description",
|
||||
required: true
|
||||
}, {
|
||||
name: "language",
|
||||
}, {
|
||||
name: "copyright",
|
||||
}, {
|
||||
name: "managingEditor",
|
||||
}, {
|
||||
name: "webMaster",
|
||||
}, {
|
||||
name: "pubDate",
|
||||
type: Date,
|
||||
format: DATEFMT
|
||||
}, {
|
||||
name: "lastBuildDate",
|
||||
type: Date,
|
||||
format: DATEFMT
|
||||
}, {
|
||||
name: "generator",
|
||||
}, {
|
||||
name: "docs",
|
||||
}, {
|
||||
name: "cloud",
|
||||
attributes: [{
|
||||
name: "domain",
|
||||
}, {
|
||||
name: "port",
|
||||
type: Number,
|
||||
format: "#"
|
||||
}, {
|
||||
name: "path",
|
||||
}, {
|
||||
name: "registerProcedure",
|
||||
}, {
|
||||
name: "protocol",
|
||||
}]
|
||||
}, {
|
||||
name: "ttl",
|
||||
type: Number,
|
||||
format: "#"
|
||||
}, {
|
||||
name: "rating",
|
||||
}, {
|
||||
name: "skipHours",
|
||||
}, {
|
||||
name: "skipDays",
|
||||
}]
|
||||
};
|
||||
|
||||
var IMAGE = {
|
||||
name: "image",
|
||||
value: [{
|
||||
name: "url",
|
||||
required: true
|
||||
}, {
|
||||
name: "title",
|
||||
required: true
|
||||
}, {
|
||||
name: "link",
|
||||
required: true
|
||||
}, {
|
||||
name: "width",
|
||||
type: Number,
|
||||
format: "#"
|
||||
}, {
|
||||
name: "height",
|
||||
type: Number,
|
||||
format: "#"
|
||||
}, {
|
||||
name: "description",
|
||||
}]
|
||||
};
|
||||
|
||||
var TEXTINPUT = {
|
||||
name: "textinput",
|
||||
value: [{
|
||||
name: "title",
|
||||
required: true
|
||||
}, {
|
||||
name: "description",
|
||||
required: true
|
||||
}, {
|
||||
name: "name",
|
||||
required: true
|
||||
}, {
|
||||
name: "link",
|
||||
required: true
|
||||
}]
|
||||
};
|
||||
|
||||
var ROOT = {
|
||||
name: "rss",
|
||||
attributes: [{
|
||||
name: "version",
|
||||
value: "2.0"
|
||||
}]
|
||||
};
|
||||
|
||||
var xmlroot = this.createElement(ROOT);
|
||||
var channel = this.createElement(CHANNEL);
|
||||
xmlroot.setValue(channel);
|
||||
|
||||
/**
|
||||
* Get the writer's root element.
|
||||
* @returns The writer's root element.
|
||||
* @type jala.XmlWriter.XmlElement
|
||||
*/
|
||||
this.getRoot = function() {
|
||||
return xmlroot;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add child elements to the channel template.
|
||||
* @param {Array} ext List of additional child elements.
|
||||
*/
|
||||
this.extendChannel = function(ext) {
|
||||
this.extend(CHANNEL, ext);
|
||||
channel = this.createElement(CHANNEL);
|
||||
xmlroot.setValue(channel);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the writer's channel element.
|
||||
* @returns The writer's channel element.
|
||||
* @type jala.XmlWriter.XmlElement
|
||||
*/
|
||||
this.getChannel = function() {
|
||||
return channel;
|
||||
};
|
||||
|
||||
/**
|
||||
* Populate the channel element with data.
|
||||
* @param {Object} data An XmlWriter-compliant object structure.
|
||||
* @returns The populated channel element.
|
||||
* @type jala.XmlWriter.XmlElement
|
||||
*/
|
||||
this.setChannel = function(data) {
|
||||
return channel.populate(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add child elements to the item template.
|
||||
* @param {Array} ext List of additional child elements.
|
||||
*/
|
||||
this.extendItem = function(ext) {
|
||||
this.extend(ITEM, ext);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a new and innocent item element.
|
||||
* @param {Object} data An XmlWriter-compliant object structure.
|
||||
* @returns A new and innocent item element.
|
||||
* @type jala.XmlWriter.XmlElement
|
||||
*/
|
||||
this.createItem = function(data) {
|
||||
var item = this.createElement(ITEM);
|
||||
item.populate(data);
|
||||
return item;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add an item element to the channel element.
|
||||
* @param {jala.XmlWriter.XmlElement} item The item element to add.
|
||||
*/
|
||||
this.addItem = function(item) {
|
||||
channel.addValue(item);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a category element to an arbitrary element.
|
||||
* @param {String} name The name of the category.
|
||||
* @param {String} domain The domain of the category.
|
||||
* @param {jala.XmlWriter.XmlElement} parent The optional parent element.
|
||||
*/
|
||||
this.addCategory = function(name, domain, parent) {
|
||||
if (!parent)
|
||||
parent = channel;
|
||||
var cat = this.createElement(CATEGORY);
|
||||
cat.populate({
|
||||
value: name,
|
||||
attributes: {domain: domain}
|
||||
});
|
||||
parent.addValue(cat);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Populate the image element with data.
|
||||
* @param {Object} data An XmlWriter-compliant object structure.
|
||||
*/
|
||||
this.setImage = function(data) {
|
||||
var image = this.createElement(IMAGE);
|
||||
image.populate(data);
|
||||
channel.setValue(image);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Populate the textInput element with data.
|
||||
* @param {Object} data An XmlWriter-compliant object structure.
|
||||
*/
|
||||
this.setTextInput = function(data) {
|
||||
var textInput = this.createElement(TEXTINPUT);
|
||||
textInput.populate(data);
|
||||
channel.setValue(textInput);
|
||||
return;
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
247
modules/jala/code/Utilities.js
Normal file
247
modules/jala/code/Utilities.js
Normal file
|
@ -0,0 +1,247 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the jala.Utilities class.
|
||||
*/
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* HelmaLib dependencies
|
||||
*/
|
||||
app.addRepository("modules/core/Number.js");
|
||||
|
||||
/**
|
||||
* Construct a utility object.
|
||||
* @class This class contains various convenience methods
|
||||
* which do not fit in any other class.
|
||||
* @returns A new utitilty object.
|
||||
* @constructor
|
||||
*/
|
||||
jala.Utilities = function() {
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a string representation of the utitility class.
|
||||
* @returns [jala.Utilities]
|
||||
* @type String
|
||||
* @ignore FIXME: JSDoc bug
|
||||
*/
|
||||
jala.Utilities.toString = function() {
|
||||
return "[jala.Utilities]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a string representation of the utitility object.
|
||||
* @returns [jala.Utilities Object]
|
||||
* @type String
|
||||
*/
|
||||
jala.Utilities.prototype.toString = function() {
|
||||
return "[jala.Utilities Object]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Default utility class instance.
|
||||
* @type jala.Utilities
|
||||
* @final
|
||||
*/
|
||||
jala.util = new jala.Utilities();
|
||||
|
||||
/**
|
||||
* Creates a random password with different levels of security.
|
||||
* @param {Number} len The length of the password (default: 8)
|
||||
* @param {Number} level The security level
|
||||
* <ul>
|
||||
* <li>0 - containing only vowels or consonants (default)</li>
|
||||
* <li>1 - throws in a number at random position</li>
|
||||
* <li>2 - throws in a number and a special character at random position</li>
|
||||
* </ul>
|
||||
* @returns The resulting password
|
||||
* @type String
|
||||
*/
|
||||
jala.Utilities.prototype.createPassword = function(len, level) {
|
||||
len = len || 8;
|
||||
level = level || 0;
|
||||
|
||||
var LETTERSONLY = 0;
|
||||
var WITHNUMBERS = 1;
|
||||
var WITHSPECIALS = 2;
|
||||
|
||||
var vowels = ['a', 'e', 'i', 'o', 'u'];
|
||||
var consonants = ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z'];
|
||||
var specials = ['.', '#', '!', '$', '%', '&', '?'];
|
||||
|
||||
var posNum = level > LETTERSONLY ? Math.floor(Math.random() * (len - 2)) : -1;
|
||||
var posSpecial = level > WITHNUMBERS ? Math.floor(Math.random() * (len - 3)) : -2;
|
||||
if (posNum == posSpecial) {
|
||||
posSpecial += 1;
|
||||
}
|
||||
|
||||
res.push();
|
||||
// loop to create characters:
|
||||
var i, rnd;
|
||||
for (i=0; i<(len-level); i+=1) {
|
||||
if(i % 2 == 0) {
|
||||
// every 2nd one is a vowel
|
||||
rnd = Math.floor(Math.random() * vowels.length);
|
||||
res.write(vowels[rnd]);
|
||||
} else {
|
||||
// every 2nd one is a consonant
|
||||
rnd = Math.floor(Math.random() * consonants.length);
|
||||
res.write(consonants[rnd]);
|
||||
}
|
||||
if (i == posNum) {
|
||||
// increased password security:
|
||||
// throw in a number at random
|
||||
rnd = Math.floor(Math.random() * specials.length);
|
||||
res.write(String(rnd + 1));
|
||||
}
|
||||
if (i == posSpecial) {
|
||||
// increased password security:
|
||||
// throw in a number at random
|
||||
rnd = Math.floor(Math.random() * specials.length);
|
||||
res.write(specials[rnd]);
|
||||
}
|
||||
}
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Static field indicating a removed object property.
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.Utilities.VALUE_REMOVED = -1;
|
||||
|
||||
/**
|
||||
* Static field indicating ad added object property.
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.Utilities.VALUE_ADDED = 1;
|
||||
|
||||
/**
|
||||
* Static field indicating a modified object property.
|
||||
* @type Number
|
||||
* @final
|
||||
*/
|
||||
jala.Utilities.VALUE_MODIFIED = 2;
|
||||
|
||||
/**
|
||||
* Returns an array containing the properties that are
|
||||
* added, removed or modified in one object compared to another.
|
||||
* @param {Object} obj1 The first of two objects which should be compared
|
||||
* @param {Object} obj2 The second of two objects which should be compared
|
||||
* @returns An Object containing all properties that are added, removed
|
||||
* or modified in the second object compared to the first.
|
||||
* Each property contains a status field with an integer value
|
||||
* which can be checked against the static jala.Utility fields
|
||||
* VALUE_ADDED, VALUE_MODIFIED and VALUE_REMOVED.
|
||||
* @type Object
|
||||
*/
|
||||
jala.Utilities.prototype.diffObjects = function(obj1, obj2) {
|
||||
var childDiff, value1, value2;
|
||||
var diff = {};
|
||||
var foundDiff = false;
|
||||
|
||||
for (var propName in obj1) {
|
||||
if (obj2[propName] === undefined || obj2[propName] === "" || obj2[propName] === null) {
|
||||
diff[propName] = {status: jala.Utilities.VALUE_REMOVED};
|
||||
foundDiff = true;
|
||||
}
|
||||
}
|
||||
for (var propName in obj2) {
|
||||
value1 = obj1[propName];
|
||||
value2 = obj2[propName];
|
||||
if (value1 == null) {
|
||||
diff[propName] = {status: jala.Utilities.VALUE_ADDED,
|
||||
value: value2};
|
||||
foundDiff = true;
|
||||
} else {
|
||||
switch (value2.constructor) {
|
||||
case HopObject:
|
||||
case Object:
|
||||
if (childDiff = this.diffObjects(value1, value2)) {
|
||||
diff[propName] = childDiff;
|
||||
foundDiff = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (value2 != null && value2 !== "") {
|
||||
if (value1 === null || value1 === undefined || value1 === "") {
|
||||
diff[propName] = {status: jala.Utilities.VALUE_ADDED,
|
||||
value: value2};
|
||||
foundDiff = true;
|
||||
} else if (value1 != value2) {
|
||||
diff[propName] = {status: jala.Utilities.VALUE_MODIFIED,
|
||||
value: value2};
|
||||
foundDiff = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return foundDiff ? diff : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Patches an object with a "diff" object created by the
|
||||
* {@link #diffObjects} method.
|
||||
* Please mind that this method is recursive, it descends
|
||||
* along the "diff" object structure.
|
||||
* @param {Object} obj The Object the diff should be applied to
|
||||
* @param {Object} diff A "diff" object created by the {@link #diffObjects} method
|
||||
* @returns The patched Object with all differences applied
|
||||
* @type Object
|
||||
*/
|
||||
jala.Utilities.prototype.patchObject = function(obj, diff) {
|
||||
var propDiff, value1;
|
||||
for (var propName in diff) {
|
||||
propDiff = diff[propName];
|
||||
value1 = obj[propName];
|
||||
if (propDiff.status != null) {
|
||||
switch (propDiff.status) {
|
||||
case jala.Utilities.VALUE_REMOVED:
|
||||
// app.debug("applyDiff(): removing property " + propName);
|
||||
delete obj[propName];
|
||||
break;
|
||||
case jala.Utilities.VALUE_ADDED:
|
||||
case jala.Utilities.VALUE_MODIFIED:
|
||||
default:
|
||||
// app.debug("applyDiff(): changing property " + propName + " to " + propDiff.value);
|
||||
obj[propName] = propDiff.value;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// app.debug("applyDiff(): descending to child object " + propName);
|
||||
this.patchObject(value1, propDiff);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
461
modules/jala/code/XmlRpcRequest.js
Normal file
461
modules/jala/code/XmlRpcRequest.js
Normal file
|
@ -0,0 +1,461 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the jala.XmlRpcRequest class.
|
||||
*/
|
||||
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A constructor for XmlRpc request objects
|
||||
* @class Instances of this class provide the necessary functionality
|
||||
* for issueing XmlRpc requests to a remote service.
|
||||
* @param {String} url The url of the XmlRpc entry point
|
||||
* @param {String} methodName The name of the method to call
|
||||
* @returns A newly created jala.XmlRpcRequest instance
|
||||
* @constructor
|
||||
*/
|
||||
jala.XmlRpcRequest = function(url, methodName) {
|
||||
/** @ignore */
|
||||
var proxy = null;
|
||||
/** @ignore */
|
||||
var timeout = {
|
||||
"connect": 0,
|
||||
"socket": 0
|
||||
};
|
||||
/** @ignore */
|
||||
var debug = false;
|
||||
/** @ignore */
|
||||
var credentials = null;
|
||||
// default input and output encoding
|
||||
/** @ignore */
|
||||
var inputEncoding = "UTF-8";
|
||||
/** @ignore */
|
||||
var outputEncoding = "UTF-8";
|
||||
|
||||
/**
|
||||
* Returns the URL of this request
|
||||
* @returns The URL of this request
|
||||
* @type java.net.URL
|
||||
*/
|
||||
this.getUrl = function() {
|
||||
return new java.net.URL(url);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the proxy host and port. For Java runtimes < 1.5 this method
|
||||
* sets the appropriate system properties (so this has an effect on
|
||||
* all requests based on java.net.URL), for all others the proxy
|
||||
* is only set for this request.
|
||||
* @param {String} proxyString The proxy string in the form 'fqdn:port'
|
||||
* (eg. my.proxy.com:3128)
|
||||
*/
|
||||
this.setProxy = function(proxyString) {
|
||||
if (proxyString && proxyString.trim()) {
|
||||
var idx = proxyString.indexOf(":");
|
||||
if (idx > 0) {
|
||||
var host = proxyString.substring(0, idx);
|
||||
var port = proxyString.substring(idx+1);
|
||||
if (host != null && port != null) {
|
||||
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.log("[Jala XmlRpc 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 object. This method will only return
|
||||
* a value if using a java runtime > 1.5
|
||||
* @returns The proxy to use for this request
|
||||
* @type java.net.Proxy
|
||||
* @see #setProxy
|
||||
*/
|
||||
this.getProxy = function() {
|
||||
return proxy;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the credentials for basic http authentication to
|
||||
* use with this request.
|
||||
* @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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the credentials of this request
|
||||
* @returns The base46 encoded credentials of this request
|
||||
* @type String
|
||||
*/
|
||||
this.getCredentials = function() {
|
||||
return credentials;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the connection timeout to the specified milliseconds.
|
||||
* @param {Number} millis The timeout to use as connection timeout
|
||||
*/
|
||||
this.setTimeout = function(millis) {
|
||||
timeout.connect = millis;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the socket timeout to the specified milliseconds.
|
||||
* @param {Number} millis The timeout to use as socket timeout
|
||||
*/
|
||||
this.setReadTimeout = function(millis) {
|
||||
timeout.socket = millis;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the connection timeout of this request
|
||||
* @returns The connection timeout value in milliseconds
|
||||
* @type Number
|
||||
*/
|
||||
this.getTimeout = function() {
|
||||
return timeout.connect;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the socket timeout of this request
|
||||
* @returns The socket timeout value in milliseconds
|
||||
* @type Number
|
||||
*/
|
||||
this.getReadTimeout = function() {
|
||||
return timeout.socket;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the name of the remote function to call
|
||||
* @returns The name of the remote function
|
||||
* @type String
|
||||
*/
|
||||
this.getMethodName = function() {
|
||||
return methodName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets both input and output encoding to the
|
||||
* specified encoding string
|
||||
* @param {String} enc The encoding to use for
|
||||
* both input and output. This must be a valid
|
||||
* java encoding string.
|
||||
*/
|
||||
this.setEncoding = function(enc) {
|
||||
inputEncoding = enc;
|
||||
outputEncoding = enc;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the input encoding to the specified encoding string
|
||||
* @param {String} enc The encoding to use for input. This must be a valid
|
||||
* java encoding string.
|
||||
*/
|
||||
this.setInputEncoding = function(enc) {
|
||||
inputEncoding = enc;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the output encoding to the specified encoding string
|
||||
* @param {String} enc The encoding to use for output. This must be a valid
|
||||
* java encoding string.
|
||||
*/
|
||||
this.setOutputEncoding = function(enc) {
|
||||
outputEncoding = enc;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the input encoding
|
||||
* @returns The input encoding used by this request
|
||||
* @type String
|
||||
*/
|
||||
this.getInputEncoding = function() {
|
||||
return inputEncoding;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the output encoding
|
||||
* @returns The output encoding used by this request
|
||||
* @type String
|
||||
*/
|
||||
this.getOutputEncoding = function() {
|
||||
return outputEncoding;
|
||||
};
|
||||
|
||||
/**
|
||||
* Enables or disables the debug mode. If enabled the xml source
|
||||
* of both request and response is included in the result properties
|
||||
* 'requestXml' and 'responseXml'
|
||||
* @param {Boolean} flag True or false.
|
||||
*/
|
||||
this.setDebug = function(flag) {
|
||||
debug = flag;
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if debug is enabled for this request, false otherwise
|
||||
* @returns True if debugging is enabled, false otherwise
|
||||
* @type Boolean
|
||||
*/
|
||||
this.debug = function() {
|
||||
return debug == true;
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
jala.XmlRpcRequest.prototype.toString = function() {
|
||||
return "[Jala XmlRpc Request]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Calling this method executes the remote method using
|
||||
* the arguments specified.
|
||||
* @returns The result of this XmlRpc request
|
||||
* @type Object
|
||||
*/
|
||||
jala.XmlRpcRequest.prototype.execute = function(/** [arg1][, arg2][, ...] */) {
|
||||
// if in debug mode, log the time the request took to event log
|
||||
if (app.__app__.debug() == true) {
|
||||
var start = new Date();
|
||||
}
|
||||
|
||||
var tz = java.util.TimeZone.getDefault();
|
||||
var reqProcessor = new Packages.org.apache.xmlrpc.XmlRpcClientRequestProcessor(tz);
|
||||
var resProcessor = new Packages.org.apache.xmlrpc.XmlRpcClientResponseProcessor(tz);
|
||||
// create the result object
|
||||
var result = {
|
||||
error: null,
|
||||
result: null,
|
||||
requestXml: null,
|
||||
responseXml: null
|
||||
};
|
||||
|
||||
// convert arguments into their appropriate java representations
|
||||
var params = new java.util.Vector();
|
||||
for (var i=0;i<arguments.length;i++) {
|
||||
params.add(jala.XmlRpcRequest.convertArgument(arguments[i]));
|
||||
}
|
||||
|
||||
var r = new Packages.org.apache.xmlrpc.XmlRpcRequest(this.getMethodName(), params);
|
||||
var requestBytes = reqProcessor.encodeRequestBytes(r, this.getOutputEncoding());
|
||||
if (this.debug() == true) {
|
||||
result.requestXml = String(new java.lang.String(requestBytes));
|
||||
}
|
||||
// open the connection
|
||||
var proxy = this.getProxy();
|
||||
var url = this.getUrl();
|
||||
var conn = proxy ? url.openConnection(proxy) : url.openConnection();
|
||||
conn.setAllowUserInteraction(false);
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("User-Agent", "Jala XmlRpc Client");
|
||||
conn.setRequestProperty("Content-Type", "text/xml");
|
||||
conn.setRequestProperty("Content-Length", requestBytes.length);
|
||||
// set timeouts if defined and possible
|
||||
if (parseFloat(java.lang.System.getProperty("java.specification.version"), 10) >= 1.5) {
|
||||
conn.setConnectTimeout(this.getTimeout());
|
||||
conn.setReadTimeout(this.getReadTimeout());
|
||||
} else {
|
||||
app.logger.debug("WARNING: timeouts can only be using a Java runtime >= 1.5");
|
||||
}
|
||||
// set authentication credentials if defined
|
||||
if (this.getCredentials() != null) {
|
||||
conn.setRequestProperty("Authorization", "Basic " + this.getCredentials());
|
||||
}
|
||||
|
||||
try {
|
||||
conn.setDoOutput(true);
|
||||
var outStream = conn.getOutputStream();
|
||||
outStream["write(byte[])"](requestBytes);
|
||||
outStream.flush();
|
||||
outStream.close();
|
||||
|
||||
if (conn.getContentLength() > 0) {
|
||||
var inStream = conn.getInputStream();
|
||||
if (this.debug() == true) {
|
||||
inStream = new java.io.BufferedInputStream(conn.getInputStream());
|
||||
var outStream = new java.io.ByteArrayOutputStream();
|
||||
var buf = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 1024);
|
||||
var bytes;
|
||||
while ((bytes = inStream.read(buf)) > -1) {
|
||||
outStream.write(buf, 0, bytes);
|
||||
}
|
||||
result.responseXml = outStream.toString(this.getInputEncoding());
|
||||
inStream.close();
|
||||
// change the inStream and don't set the input encoding of
|
||||
// the response processor, since the conversion already happened above
|
||||
inStream = new java.io.ByteArrayInputStream(outStream.toByteArray());
|
||||
}
|
||||
resProcessor.setInputEncoding(this.getInputEncoding());
|
||||
var parsedResult = resProcessor.decodeResponse(inStream);
|
||||
if (parsedResult instanceof java.lang.Exception) {
|
||||
result.error = parsedResult;
|
||||
} else {
|
||||
result.result = jala.XmlRpcRequest.convertResult(parsedResult);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
result.error = "[Jala XmlRpc Request] Error executing " + this.getMethodName()
|
||||
+ " with arguments " + jala.XmlRpcRequest.argumentsToString(arguments)
|
||||
+ ", the error is: " + e.toString();
|
||||
}
|
||||
if (app.__app__.debug() == true) {
|
||||
app.logger.debug("[Jala XmlRpc Request] (" + ((new Date()) - start) + " ms): executed '"
|
||||
+ this.getMethodName() + "' with arguments: "
|
||||
+ jala.XmlRpcRequest.argumentsToString(arguments));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper method for converting a Javascript object into
|
||||
* its appropriate Java object.
|
||||
* @param {Object} obj The Javascript object to convert
|
||||
* @returns The appropriate Java representation of the object
|
||||
* @type java.lang.Object
|
||||
*/
|
||||
jala.XmlRpcRequest.convertArgument = function(obj) {
|
||||
var result;
|
||||
if (obj instanceof Array) {
|
||||
// convert into Vector
|
||||
result = new java.util.Vector(obj.length);
|
||||
for (var i=0;i<obj.length;i++) {
|
||||
result.add(i, jala.XmlRpcRequest.convertArgument(obj[i]));
|
||||
}
|
||||
} else if (obj instanceof Date) {
|
||||
// convert into java.util.Date
|
||||
result = new java.util.Date(obj.getTime());
|
||||
} else if (typeof(obj) == "boolean" || obj instanceof Boolean) {
|
||||
result = obj;
|
||||
} else if (typeof(obj) == "string" || obj instanceof String) {
|
||||
result = obj;
|
||||
} else if (isNaN(obj) == false) {
|
||||
// convert into Integer or Double
|
||||
if (obj - obj.toFixed() > 0) {
|
||||
result = new java.lang.Double(obj);
|
||||
} else {
|
||||
result = new java.lang.Integer(obj);
|
||||
}
|
||||
} else if (obj instanceof Object) {
|
||||
// convert into Hashtable
|
||||
result = new java.util.Hashtable();
|
||||
for (var key in obj) {
|
||||
if (obj[key] != null) {
|
||||
result.put(key, jala.XmlRpcRequest.convertArgument(obj[key]));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = obj;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a Java object into its appropriate Javascript representation.
|
||||
* @param {java.lang.Object} obj The Java object to convert
|
||||
* @returns The appropriate Javascript representation of the Java object
|
||||
* @type Object
|
||||
*/
|
||||
jala.XmlRpcRequest.convertResult = function(obj) {
|
||||
var result;
|
||||
if (obj instanceof java.util.Vector) {
|
||||
// convert into Array
|
||||
result = [];
|
||||
var e = obj.elements();
|
||||
while (e.hasMoreElements()) {
|
||||
result.push(jala.XmlRpcRequest.convertResult(e.nextElement()));
|
||||
}
|
||||
} else if (obj instanceof java.util.Hashtable) {
|
||||
// convert into Object
|
||||
result = {};
|
||||
var e = obj.keys();
|
||||
var key;
|
||||
while (e.hasMoreElements()) {
|
||||
key = e.nextElement();
|
||||
result[key] = jala.XmlRpcRequest.convertResult(obj.get(key));
|
||||
}
|
||||
} else if (obj instanceof java.lang.String) {
|
||||
result = String(obj);
|
||||
} else if (obj instanceof java.lang.Number) {
|
||||
result = Number(obj);
|
||||
} else if (obj instanceof java.lang.Boolean) {
|
||||
result = Boolean(obj);
|
||||
} else if (obj instanceof java.lang.Date) {
|
||||
result = new Date(obj.getTime());
|
||||
} else {
|
||||
result = obj;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper method to format an arguments array into
|
||||
* a string useable for debugging output.
|
||||
* @param {Object} args An arguments array
|
||||
* @returns The arguments array formatted as string
|
||||
* @type String
|
||||
*/
|
||||
jala.XmlRpcRequest.argumentsToString = function(args) {
|
||||
var arr = [];
|
||||
for (var i=0;i<args.length;i++) {
|
||||
if (typeof(args[i]) == "string") {
|
||||
arr.push('"' + args[i] + '"');
|
||||
} else {
|
||||
arr.push(args[i]);
|
||||
}
|
||||
}
|
||||
return arr.join(", ");
|
||||
};
|
366
modules/jala/code/XmlWriter.js
Normal file
366
modules/jala/code/XmlWriter.js
Normal file
|
@ -0,0 +1,366 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Fields and methods of the jala.XmlWriter class.
|
||||
*/
|
||||
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new XML writer.
|
||||
* @class This class defines a generic interface to write
|
||||
* arbitrary and validating XML source code. This is done
|
||||
* by first applying data objects onto template objects,
|
||||
* both in a specified format. Then, the resulting object
|
||||
* tree is transformed into XML. Moreover, template objects
|
||||
* can be extended with other template objects to provide
|
||||
* full flexibility in inheriting subclasses.
|
||||
* @param {String} header An optional XML header.
|
||||
* @returns A new XML writer.
|
||||
* @constructor
|
||||
*/
|
||||
jala.XmlWriter = function(header) {
|
||||
var self = this;
|
||||
var XMLHEADER = header ||
|
||||
'<?xml version="1.0" encoding="iso-8859-15"?>';
|
||||
var LOCALE = java.util.Locale.ENGLISH;
|
||||
|
||||
/** @ignore FIXME: JSDoc bug */
|
||||
var write = function(str) {
|
||||
return res.write(str);
|
||||
};
|
||||
|
||||
var writeln = function(str) {
|
||||
res.write(str);
|
||||
res.write("\n");
|
||||
return;
|
||||
};
|
||||
|
||||
var getString = function(data, format) {
|
||||
if (data == null)
|
||||
return;
|
||||
switch (data.constructor) {
|
||||
case String:
|
||||
return encodeXml(data);
|
||||
case Number:
|
||||
case Date:
|
||||
if (format && data.format)
|
||||
return encodeXml(data.format(format, LOCALE));
|
||||
else if (data.toUTCString)
|
||||
return encodeXml(data.toUTCString());
|
||||
else
|
||||
return encodeXml(data.toString());
|
||||
break;
|
||||
case Object:
|
||||
return null;
|
||||
}
|
||||
return encodeXml(data.toString());
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
var XmlElement = function(data) {
|
||||
if (!data)
|
||||
throw Error("Insufficient arguments to create XmlElement");
|
||||
|
||||
var children = {};
|
||||
var properties = [
|
||||
"name",
|
||||
"attributes",
|
||||
"type",
|
||||
"required",
|
||||
"format",
|
||||
"readonly"
|
||||
];
|
||||
|
||||
if (data.value) {
|
||||
if (data.value.constructor == Object) {
|
||||
this.value = [new XmlElement(data.value)];
|
||||
} else if (data.value.constructor == Array) {
|
||||
this.value = [];
|
||||
for (var i in data.value) {
|
||||
this.value[i] = new XmlElement(data.value[i]);
|
||||
}
|
||||
} else
|
||||
throw Error("Cannot handle unknown type of template value");
|
||||
}
|
||||
|
||||
for (var i in properties) {
|
||||
var key = properties[i];
|
||||
this[key] = data[key] || null;
|
||||
}
|
||||
|
||||
if (this.attributes) {
|
||||
this.attributes = self.clone(this.attributes);
|
||||
if (this.attributes.constructor == Object)
|
||||
this.attributes = [this.attributes];
|
||||
} else {
|
||||
this.attributes = [];
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
XmlElement.toString = function() {
|
||||
return "[XmlElement constructor]";
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
XmlElement.prototype.setValue = function(element) {
|
||||
if (element.constructor != this.constructor)
|
||||
throw Error("Invalid type for XmlElement addition");
|
||||
if (!this.value)
|
||||
this.value = [];
|
||||
else {
|
||||
var pos = this.contains(element);
|
||||
if (pos > -1)
|
||||
this.value.splice(pos, 1);
|
||||
}
|
||||
this.addValue(element);
|
||||
return this;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
XmlElement.prototype.addValue = function(element) {
|
||||
if (element.constructor != this.constructor)
|
||||
throw Error("Invalid type for XmlElement addition");
|
||||
if (!this.value)
|
||||
this.value = [];
|
||||
this.value.push(element);
|
||||
return this;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
XmlElement.prototype.contains = function(element) {
|
||||
if (!this.value || !element)
|
||||
return -1;
|
||||
for (var i in this.value) {
|
||||
if (this.value[i].name == element.name)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
XmlElement.prototype.populate = function(data) {
|
||||
if (this.attributes) {
|
||||
var value;
|
||||
for (var i in this.attributes) {
|
||||
var attr = this.attributes[i];
|
||||
if (!attr.name)
|
||||
throw Error("Cannot populate unnamed attribute entry");
|
||||
if (data && data.attributes)
|
||||
value = data.attributes[attr.name];
|
||||
if (data && (data.value || data.attributes) && !value && attr.required) {
|
||||
throw Error('Missing required ' + (attr.type || Object).name + ' attribute "' +
|
||||
attr.name + '" in element <' + this.name + '> (' + value + ")");
|
||||
}
|
||||
if (value && attr.type && attr.type != value.constructor) {
|
||||
throw Error('Type mismatch in attribute "' +
|
||||
this.name + ":" + attr.name + '"');
|
||||
}
|
||||
if (value) {
|
||||
app.debug("populating attribute " + attr.name +
|
||||
" with " + value.constructor.name + ": " + value.toSource());
|
||||
}
|
||||
if (!attr.readonly) {
|
||||
attr.value = getString(value, attr.format) || attr.value ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data && data.value) // && data.value.constructor == Object)
|
||||
data = data.value;
|
||||
|
||||
if (this.value && data) {
|
||||
for (var i in this.value) {
|
||||
var element = this.value[i];
|
||||
element.populate(data[element.name]);
|
||||
}
|
||||
} else {
|
||||
if (!data && this.required)
|
||||
throw Error('Missing required element "' + this.name + '"');
|
||||
if (data && this.type && this.type != data.constructor) {
|
||||
throw Error('Type mismatch in element "' + this.name + '"');
|
||||
}
|
||||
if (data) {
|
||||
app.debug("populating element <" + this.name + "> with " +
|
||||
(this.type || Object).name + ": " + data.toSource());
|
||||
}
|
||||
if (!this.readonly)
|
||||
this.value = getString(data, this.format) || this.value;
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
XmlElement.prototype.write = function(path) {
|
||||
if (!path)
|
||||
path = "";
|
||||
|
||||
if (!this.value && !this.attributes)
|
||||
return;
|
||||
|
||||
var attrBuffer = new java.lang.StringBuffer();
|
||||
if (this.attributes) {
|
||||
for (var a in this.attributes) {
|
||||
var attr = this.attributes[a];
|
||||
if (attr.value) {
|
||||
attrBuffer.append(" " + attr.name + '="');
|
||||
attrBuffer.append(attr.value);
|
||||
attrBuffer.append('"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var attrSize = attrBuffer.length();
|
||||
if (!this.value && attrSize < 1)
|
||||
return;
|
||||
|
||||
write("<" + this.name);
|
||||
if (attrSize > 0) {
|
||||
display = true;
|
||||
write(attrBuffer.toString());
|
||||
}
|
||||
if (this.value) {
|
||||
write(">");
|
||||
if (this.value && this.value.constructor == Array) {
|
||||
for (var i in this.value)
|
||||
this.value[i].write(path+"/"+this.name);
|
||||
} else
|
||||
write(this.value);
|
||||
write("</" + this.name + ">\n");
|
||||
} else
|
||||
write("/>\n");
|
||||
return;
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
XmlElement.prototype.toString = function() {
|
||||
return "[XmlElement: " + this.toSource() + "]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a newly created XML element.
|
||||
* @param {Object} data The XML data as object tree.
|
||||
* @returns The resulting XML element.
|
||||
* @type jala.XmlWriter.XmlElement
|
||||
*/
|
||||
this.createElement = function(data) {
|
||||
return new XmlElement(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the root XML element of this writer.
|
||||
* @returns The root XML element.
|
||||
* @type jala.XmlWriter.XmlElement
|
||||
*/
|
||||
this.getRoot = function() {
|
||||
return new XmlElement({});
|
||||
};
|
||||
|
||||
/**
|
||||
* Extend a template object.
|
||||
* @param {Object} template The template object.
|
||||
* @param {Object} ext The extension object.
|
||||
* @returns The XML writer.
|
||||
* @type jala.XmlWriter
|
||||
*/
|
||||
this.extend = function(template, ext) {
|
||||
if (ext.constructor == Object)
|
||||
ext = [ext];
|
||||
if (ext.constructor == Array) {
|
||||
for (var i in ext)
|
||||
template.value.push(ext[i]);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a namespace to this writer.
|
||||
* @param {String} name The name of the namespace.
|
||||
* @param {String} url The URL string of the namespace.
|
||||
* @returns The XML root element.
|
||||
* @type jala.XmlWriter.XmlElement
|
||||
*/
|
||||
this.addNamespace = function(name, url) {
|
||||
var ref = this.getRoot();
|
||||
ref.attributes.push({
|
||||
name: "xmlns:" + name,
|
||||
value: url
|
||||
});
|
||||
return ref;
|
||||
};
|
||||
|
||||
/**
|
||||
* Write the XML to the response buffer.
|
||||
*/
|
||||
this.write = function() {
|
||||
res.contentType = "text/xml";
|
||||
writeln(XMLHEADER);
|
||||
this.getRoot().write();
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the XML output as string.
|
||||
* @returns The XML output.
|
||||
* @type String
|
||||
*/
|
||||
this.toString = function() {
|
||||
res.push();
|
||||
this.write();
|
||||
return res.pop();
|
||||
};
|
||||
|
||||
/**
|
||||
* Clone this XML writer.
|
||||
* @param {Object} The clone templare.
|
||||
* @returns The cloned XML writer.
|
||||
* @type jala.XmlWriter
|
||||
*/
|
||||
this.clone = function(obj) {
|
||||
if (!obj || typeof obj != "object")
|
||||
return obj;
|
||||
var copy = new obj.constructor;
|
||||
for (var i in obj) {
|
||||
if (obj[i].constructor == Object ||
|
||||
obj[i].constructor == Array)
|
||||
copy[i]= this.clone(obj[i]);
|
||||
else
|
||||
copy[i] = obj[i];
|
||||
}
|
||||
return copy;
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
74
modules/jala/code/all.js
Normal file
74
modules/jala/code/all.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
||||
//
|
||||
// Copyright 2004 ORF Online und Teletext GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// $Revision$
|
||||
// $LastChangedBy$
|
||||
// $LastChangedDate$
|
||||
// $HeadURL$
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview Wrapper for automatic inclusion of all Jala modules.
|
||||
*/
|
||||
|
||||
|
||||
// Define the global namespace for Jala modules
|
||||
if (!global.jala) {
|
||||
global.jala = {};
|
||||
}
|
||||
|
||||
|
||||
(function() {
|
||||
var packages = [
|
||||
"AsyncRequest",
|
||||
"BitTorrent",
|
||||
"Date",
|
||||
"DnsClient",
|
||||
"Captcha",
|
||||
"Form",
|
||||
"History",
|
||||
"HtmlDocument",
|
||||
"HopObject",
|
||||
"I18n",
|
||||
"ImageFilter",
|
||||
"IndexManager",
|
||||
"ListRenderer",
|
||||
"Mp3",
|
||||
"PodcastWriter",
|
||||
"RemoteContent",
|
||||
"Rss20Writer",
|
||||
"Utilities",
|
||||
"XmlRpcRequest",
|
||||
"XmlWriter"
|
||||
];
|
||||
var jalaDir = getProperty("jala.dir", "modules/jala");
|
||||
for (var i in packages) {
|
||||
app.addRepository(jalaDir + "/code/" + packages[i] + ".js");
|
||||
}
|
||||
return;
|
||||
})();
|
||||
|
||||
|
||||
/**
|
||||
* Get a string representation of the Jala library.
|
||||
* @returns [Jala JavaScript Application Library]
|
||||
* @type String
|
||||
*/
|
||||
jala.toString = function() {
|
||||
return "[Jala JavaScript Application Library]";
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue