coliver 2003/03/16 16:32:35
Modified: src/java/org/apache/cocoon/components/flow/javascript
JSCocoon.java JSErrorReporter.java
JavaScriptInterpreter.java system.js
Added: src/java/org/apache/cocoon/components/flow/javascript
Database.js xmlForm.js
Log:
fixed script reloading and started preparing for refactoring of FOM
Revision Changes Path
1.5 +5 -14
cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/JSCocoon.java
Index: JSCocoon.java
===================================================================
RCS file:
/home/cvs/cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/JSCocoon.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- JSCocoon.java 16 Mar 2003 18:03:53 -0000 1.4
+++ JSCocoon.java 17 Mar 2003 00:32:35 -0000 1.5
@@ -91,7 +91,6 @@
{
protected static String OBJECT_SOURCE_RESOLVER = "source-resolver";
protected JavaScriptInterpreter interpreter;
- protected Scriptable scope;
protected NativeArray parameters;
protected Environment environment;
protected ComponentManager manager;
@@ -103,15 +102,6 @@
return "Cocoon";
}
- public void setScope(Scriptable scope)
- {
- this.scope = scope;
- }
-
- public Scriptable getScope()
- {
- return scope;
- }
public void setParameters(NativeArray parameters)
{
@@ -208,8 +198,9 @@
org.mozilla.javascript.Context cx =
org.mozilla.javascript.Context.getCurrentContext();
try {
- Script script = interpreter.compileScript(cx, environment, filename);
- return script.exec(cx, ScriptableObject.getTopLevelScope(this));
+ Scriptable scope = getParentScope();
+ Script script = interpreter.compileScript(cx, scope, environment,
filename);
+ return script.exec(cx, scope);
} catch (JavaScriptException e) {
throw e;
} catch (Exception e) {
@@ -273,7 +264,7 @@
*/
public void jsFunction_createSession()
{
- interpreter.setSessionScope(environment, scope);
+ interpreter.setSessionScope(environment, getParentScope());
}
/**
1.4 +6 -4
cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/JSErrorReporter.java
Index: JSErrorReporter.java
===================================================================
RCS file:
/home/cvs/cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/JSErrorReporter.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- JSErrorReporter.java 16 Mar 2003 17:49:12 -0000 1.3
+++ JSErrorReporter.java 17 Mar 2003 00:32:35 -0000 1.4
@@ -44,9 +44,11 @@
int line, String lineSrc,
int column)
{
- return new EvaluatorException(getErrorMessage("msg.error", message,
- sourceName, line,
- lineSrc, column));
+ String errMsg = getErrorMessage("msg.error", message,
+ sourceName, line,
+ lineSrc, column);
+ System.err.println(errMsg);
+ return new EvaluatorException(errMsg);
}
/**
1.4 +145 -125
cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/JavaScriptInterpreter.java
Index: JavaScriptInterpreter.java
===================================================================
RCS file:
/home/cvs/cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/JavaScriptInterpreter.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- JavaScriptInterpreter.java 16 Mar 2003 17:49:12 -0000 1.3
+++ JavaScriptInterpreter.java 17 Mar 2003 00:32:35 -0000 1.4
@@ -86,6 +86,18 @@
public class JavaScriptInterpreter extends AbstractInterpreter
implements Configurable, Initializable
{
+ /**
+ * LAST_EXEC_TIME
+ * A long value is stored under this key in each top level JavaScript
+ * thread scope object. When you enter a context any scripts whose
+ * modification time is later than this value will be recompiled and reexecuted,
+ * and this value will be updated to the current time.
+ */
+ private final static String LAST_EXEC_TIME = "__PRIVATE_LAST_EXEC_TIME__";
+
+ /**
+ * Key for storing a JavaScript global scope object in the Cocoon session
+ */
public static final String USER_GLOBAL_SCOPE = "JavaScript GLOBAL SCOPE";
// This is the only optimization level that supports continuations
@@ -93,18 +105,60 @@
static int OPTIMIZATION_LEVEL = -2;
/**
- * List of <code>Source</code> objects that represent files to be
- * read in by the JavaScript interpreter.
- */
- protected List scripts = new ArrayList();
-
- /**
* When was the last time we checked for script modifications. Used
* only if [EMAIL PROTECTED] #reloadScripts} is true.
*/
protected long lastTimeCheck = 0;
+
+ /**
+ * Shared global scope for scripts and other immutable objects
+ */
JSGlobal scope;
- List compiledScripts = Collections.synchronizedList(new ArrayList());
+
+ /**
+ * List of <code>String</code> objects that represent files to be
+ * read in by the JavaScript interpreter.
+ */
+ List topLevelScripts = new ArrayList();
+
+ class ScriptSourceEntry {
+ final private Source source;
+ private Script script;
+ private long compileTime;
+
+ public ScriptSourceEntry(Source source) {
+ this.source = source;
+ }
+
+ public ScriptSourceEntry(Source source, Script script, long t) {
+ this.source = source;
+ this.script = script;
+ this.compileTime = t;
+ }
+
+ public Source getSource() {
+ return source;
+ }
+
+ public Script getScript(Context context, Scriptable scope,
+ boolean refresh)
+ throws Exception {
+ if (refresh) {
+ source.refresh();
+ }
+ if (script == null || compileTime < source.getLastModified()) {
+ script = compileScript(context, scope, source);
+ compileTime = source.getLastModified();
+ }
+ return script;
+ }
+ }
+ /**
+ * Mapping of String objects (source uri's) to ScriptSourceEntry's
+ *
+ */
+ Map compiledScripts = new HashMap();
+
JSErrorReporter errorReporter;
boolean enableDebugger = false;
org.mozilla.javascript.tools.debugger.Main debugger;
@@ -153,6 +207,7 @@
Context context = Context.enter();
context.setOptimizationLevel(OPTIMIZATION_LEVEL);
+ context.setCompileFunctionsWithDynamicScope(true);
context.setGeneratingDebug(true);
// add support for Rhino objects to JXPath
JXPathIntrospector.registerDynamicClass(org.mozilla.javascript.Scriptable.class,
@@ -285,9 +340,7 @@
* @return a <code>Scriptable</code> value
* @exception Exception if an error occurs
*/
- protected Scriptable enterContext(Environment environment,
- boolean needsExec,
- List sourcesToBeCompiled)
+ protected Scriptable enterContext(Environment environment)
throws Exception
{
Context context = Context.enter();
@@ -297,7 +350,6 @@
context.setErrorReporter(errorReporter);
Scriptable thrScope = null;
- compileScripts(context, environment, sourcesToBeCompiled);
// Try to retrieve the scope object from the session instance. If
// no scope is found, we create a new one, but don't place it in
@@ -312,7 +364,12 @@
// The Cocoon object exported to JavaScript needs to be setup here
JSCocoon cocoon;
+ boolean newScope = false;
+ long lastExecTime = 0;
if (thrScope == null) {
+
+ newScope = true;
+
thrScope = context.newObject(scope);
thrScope.setPrototype(scope);
@@ -325,26 +382,65 @@
// to the interpreter object, and some Cocoon objects. See
// JSCocoon for more details.
Object args[] = {};
- cocoon = (JSCocoon)context.newObject(scope, "Cocoon", args);
- ((JSCocoon)cocoon).setInterpreter(this);
- ((JSCocoon)cocoon).setScope(thrScope);
+ cocoon = (JSCocoon)context.newObject(thrScope, "Cocoon", args);
+ cocoon.setInterpreter(this);
+ cocoon.setParentScope(thrScope);
thrScope.put("cocoon", thrScope, cocoon);
- needsExec = true;
+ ((ScriptableObject)thrScope).defineProperty(LAST_EXEC_TIME,
+ new Long(0),
+ ScriptableObject.DONTENUM |
+ ScriptableObject.PERMANENT);
+
} else {
cocoon = (JSCocoon)thrScope.get("cocoon", thrScope);
+ lastExecTime = ((Long)thrScope.get(LAST_EXEC_TIME,
+ thrScope)).longValue();
+
}
// We need to setup the JSCocoon object according to the current
// request. Everything else remains the same.
cocoon.setContext(manager, environment);
- if (needsExec) {
- for (int i = 0; i < compiledScripts.size(); i++) {
- Script compiledScript = (Script)compiledScripts.get(i);
- compiledScript.exec(context, thrScope);
- }
+ // Check if we need to compile and/or execute scripts
+ List execList = new ArrayList();
+ boolean needsRefresh = false;
+ synchronized (this) {
+ if (reloadScripts) {
+ long now = System.currentTimeMillis();
+ if (now >= lastTimeCheck + checkTime) {
+ needsRefresh = true;
+ }
+ lastTimeCheck = now;
+ }
+ if (needsRefresh || needResolve.size() > 0) {
+ topLevelScripts.addAll(needResolve);
+ if (!newScope && !needsRefresh) {
+ execList.addAll(needResolve);
+ } else {
+ execList.addAll(topLevelScripts);
+ }
+ needResolve.clear();
+ }
+ }
+ thrScope.put(LAST_EXEC_TIME, thrScope,
+ new Long(System.currentTimeMillis()));
+ for (int i = 0; i < execList.size(); i++) {
+ String sourceURI = (String)execList.get(i);
+ ScriptSourceEntry entry =
+ (ScriptSourceEntry)compiledScripts.get(sourceURI);
+ if (entry == null) {
+ Source src = environment.resolveURI(sourceURI);
+ entry = new ScriptSourceEntry(src);
+ compiledScripts.put(sourceURI, entry);
+ }
+ // Compile the script if necessary
+ Script script = entry.getScript(context, thrScope, needsRefresh);
+ long lastMod = entry.getSource().getLastModified();
+ // Execute the script if necessary
+ if (lastExecTime == 0 || lastMod > lastExecTime) {
+ script.exec(context, thrScope);
+ }
}
-
-
return thrScope;
}
@@ -363,18 +459,6 @@
Context.exit();
}
- private void compileScripts(Context cx, Environment environment, List sources)
- throws Exception
- {
- if (getLogger().isDebugEnabled()) {
- getLogger().debug("Reading scripts");
- }
- Iterator iter = sources.iterator();
- while (iter.hasNext()) {
- Source src = (Source)iter.next();
- compileScript(cx, src);
- }
- }
/**
* Compile filename as JavaScript code
@@ -385,90 +469,32 @@
*/
public Script compileScript(Context cx,
+ Scriptable scope,
Environment environment,
String fileName) throws Exception {
Source src = environment.resolveURI(fileName);
if (src == null) {
throw new ResourceNotFoundException(fileName + ": not found");
}
- return compileScript(cx, src);
+ ScriptSourceEntry entry =
+ (ScriptSourceEntry)compiledScripts.get(src.getURI());
+ Script compiledScript = null;
+ if (entry == null) {
+ compiledScripts.put(src.getURI(),
+ entry = new ScriptSourceEntry(src));
+ }
+ compiledScript = entry.getScript(cx, this.scope, false);
+ return compiledScript;
}
- private Script compileScript(Context cx, Source src) throws Exception {
+ private Script compileScript(Context cx, Scriptable scope,
+ Source src) throws Exception {
InputStream is = src.getInputStream();
Reader reader = new BufferedReader(new InputStreamReader(is));
- Script compiledScript = cx.compileReader(scope, reader,
+ Script compiledScript = cx.compileReader(this.scope, reader,
src.getURI(),
1, null);
- compiledScripts.add(compiledScript);
- return compiledScript;
- }
-
- /**
- * Reloads any modified script files.
- *
- * <p>It checks to see if any of the files already read in (those
- * present in the <code>scripts</code> hash map) have been
- * modified.
- *
- * <p>It also checks to see if any script files have been registered
- * with the interpreter since the last call to
- * <code>checkForModifiedScripts</code>. These files are stored in
- * the temporary array <code>needResolve</code>. If any such files
- * are found, they are read in.
- *
- * @param environment an <code>Environment</code> value
- * @param toBeCompiled output parameter: the list of <code>Source</code>
objects to be compiled
- * @return true if any existing Source script has changed
- */
- public boolean checkForModifiedScripts(Environment environment,
- List toBeCompiled)
- throws Exception
- {
- boolean needsRefresh = false;
- if (reloadScripts
- && System.currentTimeMillis() >= lastTimeCheck + checkTime) {
- // FIXME: should we worry about synchronization?
- for (int i = 0, size = scripts.size(); i < size; i++) {
- Source src = (Source)scripts.get(i);
- src.refresh();
- getLogger().debug("Checking " + src.getURI()
- + ", source " + src
- + ", last modified " + src.getLastModified()
- + ", last time check " + lastTimeCheck);
- if (src.getLastModified() > lastTimeCheck) {
- needsRefresh = true;
- break;
- }
- }
- }
-
- // FIXME: remove the need for synchronization
- synchronized (this) {
- int size = needResolve.size();
-
- // If there's no need to re-read any file, and no files
- // have been requested to be read since the last time,
- // don't do anything.
- if (!needsRefresh && size == 0) {
- lastTimeCheck = System.currentTimeMillis();
- return false;
- }
-
- for (int i = 0; i < size; i++) {
- String source = (String)needResolve.get(i);
- Source src = environment.resolveURI(source);
- scripts.add(src);
- toBeCompiled.add(src);
- }
- needResolve.clear();
- }
-
- // Update the time of the last check. If an exception occurs, this
- // is not executed, so the next request will force a reparse of
- // the script files because of an old time stamp.
- lastTimeCheck = System.currentTimeMillis();
- return needsRefresh;
+ return compiledScript;
}
/**
@@ -487,14 +513,11 @@
throws Exception
{
Scriptable thrScope = null;
- List toBeCompiled = new ArrayList();
- boolean needsRefresh = checkForModifiedScripts(environment, toBeCompiled);
try {
- thrScope = enterContext(environment, needsRefresh, toBeCompiled);
+ thrScope = enterContext(environment);
Context context = Context.getCurrentContext();
JSCocoon cocoon = (JSCocoon)thrScope.get("cocoon", thrScope);
-
if (enableDebugger) {
final Scriptable s = thrScope;
debugger.setScopeProvider(
@@ -504,18 +527,6 @@
if (!debugger.isVisible())
debugger.setVisible(true);
}
-
- Object callFunction = thrScope.get("callFunction", thrScope);
- if (callFunction == Scriptable.NOT_FOUND)
- throw new RuntimeException("Cannot find 'callFunction' "
- + "(system.js not loaded?)");
-
- Object fun = thrScope.get(funName, thrScope);
- if (fun == Scriptable.NOT_FOUND)
- throw new RuntimeException("'" + funName + "' is undefined!");
- if (!(fun instanceof Function))
- throw new RuntimeException("'" + funName + "' is not a function!");
-
int size = (params != null ? params.size() : 0);
Object[] funArgs = new Object[size];
NativeArray parameters = new NativeArray(size);
@@ -523,13 +534,22 @@
for (int i = 0; i < size; i++) {
Interpreter.Argument arg = (Interpreter.Argument)params.get(i);
funArgs[i] = arg.value;
+ if (arg.name == null) arg.name = "";
parameters.put(arg.name, parameters, arg.value);
}
}
cocoon.setParameters(parameters);
NativeArray funArgsArray = new NativeArray(funArgs);
+ Object fun = ScriptableObject.getProperty(thrScope, funName);
+ if (fun == Scriptable.NOT_FOUND) {
+ fun = "funName";
+ }
Object callFunArgs[] = { fun, funArgsArray };
- ((Function) callFunction).call(context, thrScope, thrScope,
callFunArgs);
+ Object callFun = ScriptableObject.getProperty(thrScope, "callFunction");
+ if (callFun == Scriptable.NOT_FOUND) {
+ callFun = "callFunction";
+ }
+ ScriptRuntime.call(context, callFun, thrScope, callFunArgs, thrScope);
}
catch (JavaScriptException ex) {
Context.reportError(ToolErrorReporter.getMessage("msg.uncaughtJSException",
@@ -565,7 +585,7 @@
JSWebContinuation jswk = (JSWebContinuation)wk.getUserObject();
JSCocoon cocoon = jswk.getJSCocoon();
cocoon.setContext(manager, environment);
- final Scriptable kScope = cocoon.getScope();
+ final Scriptable kScope = cocoon.getParentScope();
if (enableDebugger) {
debugger.setScopeProvider(
1.2 +0 -297
cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/system.js
Index: system.js
===================================================================
RCS file:
/home/cvs/cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/system.js,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- system.js 9 Mar 2003 00:08:51 -0000 1.1
+++ system.js 17 Mar 2003 00:32:35 -0000 1.2
@@ -118,301 +118,4 @@
}
}
-//
-// XMLForm Support
-//
-
-/**
- * Creates a new JavaScript wrapper of a Form object
- * see org.apache.cocoon.components.xmlform.Form
- * @param id form id
- * @param validatorNS Namespace of validator
- * @param validatorDoc Validator document
- */
-
-function XForm(id, validatorNS, validatorDoc) {
- cocoon.createSession();
- this.id = id;
- this.lastContinuation = null;
- XForm.forms[id] = this;
- this.validatorNS = validatorNS;
- this.validatorDoc = validatorDoc;
- this.dead = false;
-}
-
-/**
- * Global variable that stores XForm instances by id
- */
-XForm.forms = {};
-
-/**
- * Return the model object of this form
- * @return a Java bean, JavaScript, DOM, or JDOM object
- */
-XForm.prototype.getModel = function() {
- return this.form.getModel();
-}
-
-/**
- * Set the model object of this form
- * @param model Any Java bean, JavaScript, DOM, or JDOM object
- */
-XForm.prototype.setModel = function(model) {
- this.form =
- new Packages.org.apache.cocoon.components.xmlform.Form(this.id,
- model);
- this.context =
- Packages.org.apache.commons.jxpath.JXPathContext.newContext(model);
- this.form.setAutoValidate(false);
- if (this.validatorNS != undefined && this.validatorDoc != undefined) {
- this._setValidator(this.validatorNS, this.validatorDoc);
- }
-}
-
-/**
- * Creates a new web continuation
- * @param lastCont previous web continuation
- * @param timeToLive expiration time for this continuation
- * @return a new WebContinuation instance
- */
-XForm.prototype.start = function(lastCont, timeToLive) {
- var k = new Continuation();
- var kont = new WebContinuation(cocoon, k,
- lastCont, timeToLive);
- return kont;
-}
-
-/**
- * Adds a violation to this form
- * @param xpath xpath expression of field that contains invalid data
- * @param message error message
- */
-XForm.prototype.addViolation = function(xpath, message) {
- var violation =
- new Packages.org.apache.cocoon.components.validation.Violation();
- violation.path = xpath;
- violation.message = message;
- var list = new java.util.LinkedList();
- list.add(violation);
- try {
- this.form.addViolations(list);
- } catch (e) {
- print(e);
- if (e instanceof java.lang.Throwable) {
- e.printStackTrace();
- }
- }
-}
-
-/**
- * Computes the value of an xpath expression against the model of this form
- * @param expr xpath expression
- * @return result of computing <code>expr</code>
- */
-XForm.prototype.getValue = function(expr) {
- return this.context.getValue(expr);
-}
-
-/**
- * Returns an iterator over a nodeset value of an xpath expression evaluated
- * against the model of this form
- * @param expr xpath expression
- * @return java.util.Iterator representing a nodeset
- */
-XForm.prototype.iterate = function(expr) {
- return this.context.iterate(expr);
-}
-
-XForm.prototype._sendView = function(uri, lastCont, timeToLive) {
- var k = new Continuation();
- var kont = new WebContinuation(cocoon, k, lastCont, timeToLive);
- var bizData = this.form.getModel();
- if (bizData == undefined) {
- bizData = null;
- }
- cocoon.forwardTo("cocoon://" + cocoon.environment.getURIPrefix() + uri,
- bizData, kont);
- this.lastContinuation = kont;
- suicide();
-}
-
-/**
- * Sends view to presentation pipeline and waits for subsequent submission.
- * Automatically resends view if validation fails.
- * Creates two continuations: one immediately before the page is sent
- * and one immediately after. These are used to implement automated support
- * for back/forward navigation in the form. When you move forward in the
- * form the second continuation is invoked. When you move back from the
- * following page the first continuation is invoked.
- * @param phase view to send (and phase to validate)
- * @param uri presentation pipeline resource identifier
- * @param validator optional function invoked to perform validation
- */
-XForm.prototype.sendView = function(phase, uri, validator) {
- var lastCont = this.lastContinuation;
- this.form.clearViolations();
- var view = this.form.getFormView(cocoon.environment.objectModel);
- while (true) {
- // create a continuation, the invocation of which will resend
- // the page: this is used to implement <xf:submit continuation="back">
- var k = this.start(lastCont);
- if (cocoon.request == null) {
- // this continuation has been invalidated
- this.dead = true;
- handleInvalidContinuation();
- suicide();
- }
- // reset the view in case this is a re-invocation of a continuation
- cocoon.request.setAttribute("view", view);
- try {
- this.form.save(cocoon.environment.objectModel, "request");
- } catch (e if (e instanceof java.lang.IllegalStateException)) {
- if (cocoon.session.getAttribute(this.id) != null) {
- // someone else has taken my session
- this.dead = true;
- cocoon.removeSession();
- handleInvalidContinuation();
- suicide();
- }
- throw e;
- }
- this._sendView(uri, k);
- // _sendView creates a continuation, the invocation of which
- // will return right here: it is used to implement
- // <xf:submit continuation="forward">
- if (this.dead || cocoon.request == null) {
- // this continuation has been invalidated
- handleInvalidContinuation();
- suicide();
- }
- this.form.populate(cocoon.environment.objectModel);
- if (validator != undefined) {
- validator(this);
- }
- this.form.validate(phase);
- if (this.form.violationsAsSortedSet == null ||
- this.form.violationsAsSortedSet.size() == 0) {
- break;
- }
- }
-}
-
-XForm.prototype._setValidator = function(schNS, schDoc) {
- // if validator params are not specified, then
- // there is no validation by default
- if (schNS == null || schDoc == null ) return null;
- var resolver = cocoon.environment;
- var schemaSrc = resolver.resolveURI( schDoc );
- try {
- var is =
Packages.org.apache.cocoon.components.source.SourceUtil.getInputSource(schemaSrc);
- var schf =
Packages.org.apache.cocoon.components.validation.SchemaFactory.lookup ( schNS );
- var sch = schf.compileSchema ( is );
- this.form.setValidator(sch.newValidator());
- } finally {
- resolver.release(schemaSrc);
- }
-}
-
-/**
- * Sends view to presentation pipeline but doesn't wait for submission
- * @param view view to send
- * @param uri presentation pipeline uri
- */
-
-XForm.prototype.finish = function(view, uri) {
- try {
- this.form.save(cocoon.environment.objectModel, "request");
- } catch (e if (e instanceof java.lang.IllegalStateException)) {
- if (cocoon.session.getAttribute(this.id) != null) {
- // someone else has taken my session
- this.dead = true;
- cocoon.removeSession();
- handleInvalidContinuation();
- suicide();
- }
- throw e;
- }
- cocoon.forwardTo("cocoon://" + cocoon.environment.getURIPrefix() + uri,
- this.form.getModel(), null);
- delete XForm.forms[this.id]; // delete myself
- this.dead = true;
- cocoon.removeSession();
- if (this.lastContinuation != null) {
- this.lastContinuation.invalidate();
- this.lastContinuation = null;
- }
-
-}
-
-/**
- * Entry point to a flow-based XMLForm application. Replaces the functionality
- * of XMLForm actions.
- * @param application Name of a JavaScript function that represents the page flow
for a form
- * @param id form id
- * @param validator_ns XML namespace of validator
- * @param validator_doc validator document
- */
-
-function xmlForm(application, id, validator_ns, validator_doc) {
- if (cocoon.request == null) {
- handleInvalidContinuation("");
- return;
- }
- function getCommand() {
- var enum_ = cocoon.request.parameterNames;
- var command = undefined;
- while (enum_.hasMoreElements()) {
- var paramName = enum_.nextElement();
- // search for the command
- if
(paramName.startsWith(Packages.org.apache.cocoon.Constants.ACTION_PARAM_PREFIX)) {
- command =
-
paramName.substring(Packages.org.apache.cocoon.Constants.ACTION_PARAM_PREFIX.length(),
paramName.length());
- break;
- }
- }
- // command encodes the continuation id for "back" or "next" actions
- return command;
- }
- var command = getCommand();
- if (command != undefined) {
- var xform = XForm.forms[id];
- if (xform != undefined) {
- // invoke a continuation
- var continuationsMgr =
-
cocoon.componentManager.lookup(Packages.org.apache.cocoon.components.flow.ContinuationsManager.ROLE);
- var wk = continuationsMgr.lookupWebContinuation(command);
- cocoon.componentManager.release(continuationsMgr);
- if (wk != null) {
- var jswk = wk.userObject;
- xform.form.clearViolations();
- jswk.continuation(jswk);
- }
- }
- handleInvalidContinuation(command);
- return;
- }
- // Just start a new instance of the application
- cocoon.session.removeAttribute(id);
- this[application](new XForm(id, validator_ns, validator_doc));
-}
-
-//
-// Prototype Database API
-//
-// TBD: Move this Database stuff to its own library outside of flow
-//
-
-defineClass("org.apache.cocoon.components.flow.javascript.ScriptableConnection");
-defineClass("org.apache.cocoon.components.flow.javascript.ScriptableResult");
-
-Database.getConnection = function(selectorValue) {
- var selector =
cocoon.componentManager.lookup(Packages.org.apache.avalon.excalibur.datasource.DataSourceComponent.ROLE
+ "Selector");
- try {
- var ds = selector.select(selectorValue);
- return new Database(ds.getConnection());
- } finally {
- cocoon.componentManager.release(selector);
- }
-}
-
1.1
cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/Database.js
Index: Database.js
===================================================================
//
// Prototype Database API
//
// TBD: Move this Database stuff to its own library outside of flow
//
defineClass("org.apache.cocoon.components.flow.javascript.ScriptableConnection");
defineClass("org.apache.cocoon.components.flow.javascript.ScriptableResult");
Database.getConnection = function(selectorValue) {
var selector =
cocoon.componentManager.lookup(Packages.org.apache.avalon.excalibur.datasource.DataSourceComponent.ROLE
+ "Selector");
try {
var ds = selector.select(selectorValue);
return new Database(ds.getConnection());
} finally {
cocoon.componentManager.release(selector);
}
}
1.1
cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/xmlForm.js
Index: xmlForm.js
===================================================================
//
// XMLForm Support
//
/**
* Creates a new JavaScript wrapper of a Form object
* see org.apache.cocoon.components.xmlform.Form
* @param id [String] unique form id
* @param validatorNS [String] Namespace of validator
* @param validatorDoc [String] Validator document
* @param scope [String] either "request" or "session"
*/
function XForm(id, validatorNS, validatorDoc, scope) {
if (scope == "session") {
cocoon.createSession();
}
this.id = id;
this.lastContinuation = null;
XForm.forms[id] = this;
this.validatorNS = validatorNS;
this.validatorDoc = validatorDoc;
this.dead = false;
}
/**
* Global variable that stores XForm instances by id
*/
XForm.forms = {};
/**
* Return the model object of this form
* @return a Java bean, JavaScript, DOM, or JDOM object
*/
XForm.prototype.getModel = function() {
return this.form.getModel();
}
/**
* Set the model object of this form
* @param model [Object] Any Java bean, JavaScript, DOM, or JDOM object
*/
XForm.prototype.setModel = function(model) {
this.form =
new Packages.org.apache.cocoon.components.xmlform.Form(this.id,
model);
this.context =
Packages.org.apache.commons.jxpath.JXPathContext.newContext(model);
this.form.setAutoValidate(false);
if (this.validatorNS != undefined && this.validatorDoc != undefined) {
this._setValidator(this.validatorNS, this.validatorDoc);
}
}
/**
* Creates a new web continuation
* @param lastCont [WebContinuation] previous web continuation
* @param timeToLive [Number] expiration time for this continuation in milliseconds
* @return [WebContinuation] a new WebContinuation instance
*/
XForm.prototype.start = function(lastCont, timeToLive) {
var k = new Continuation();
var kont = new WebContinuation(cocoon, k,
lastCont, timeToLive);
return kont;
}
/**
* Adds a violation to this form
* @param xpath [String] xpath location of field that contains invalid data
* @param message [String] error message
*/
XForm.prototype.addViolation = function(xpath, message) {
var violation =
new Packages.org.apache.cocoon.components.validation.Violation();
violation.path = xpath;
violation.message = message;
var list = new java.util.LinkedList();
list.add(violation);
try {
this.form.addViolations(list);
} catch (e) {
print(e);
if (e instanceof java.lang.Throwable) {
e.printStackTrace();
}
}
}
/**
* Computes the value of an xpath expression against the model of this form
* @param expr [String] xpath expression
* @return [Object] result of computing <code>expr</code>
*/
XForm.prototype.getValue = function(expr) {
return this.context.getValue(expr);
}
/**
* Returns an iterator over a nodeset value of an xpath expression evaluated
* against the model of this form
* @param expr [String] xpath expression
* @return [java.util.Iterator] representing a nodeset
*/
XForm.prototype.iterate = function(expr) {
return this.context.iterate(expr);
}
XForm.prototype._sendView = function(uri, lastCont, timeToLive) {
var k = new Continuation();
var kont = new WebContinuation(cocoon, k, lastCont, timeToLive);
var bizData = this.form.getModel();
if (bizData == undefined) {
bizData = null;
}
cocoon.forwardTo("cocoon://" + cocoon.environment.getURIPrefix() + uri,
bizData, kont);
this.lastContinuation = kont;
suicide();
}
/**
* Sends view to presentation pipeline and waits for subsequent submission.
* Automatically resends view if validation fails.
* Creates two continuations: one immediately before the page is sent
* and one immediately after. These are used to implement automated support
* for back/forward navigation in the form. When you move forward in the
* form the second continuation is invoked. When you move back from the
* following page the first continuation is invoked.
* @param phase [String] phase to validate
* @param uri [String] presentation pipeline resource identifier of view
* @param validator [Function] optional function invoked to perform validation
*/
XForm.prototype.sendView = function(phase, uri, validator) {
var lastCont = this.lastContinuation;
this.form.clearViolations();
var view = this.form.getFormView(cocoon.environment.objectModel);
while (true) {
// create a continuation, the invocation of which will resend
// the page: this is used to implement <xf:submit continuation="back">
var k = this.start(lastCont);
if (cocoon.request == null) {
// this continuation has been invalidated
this.dead = true;
handleInvalidContinuation();
suicide();
}
// reset the view in case this is a re-invocation of a continuation
cocoon.request.setAttribute("view", view);
try {
this.form.save(cocoon.environment.objectModel, "request");
} catch (e if (e instanceof java.lang.IllegalStateException)) {
if (cocoon.session.getAttribute(this.id) != null) {
// someone else has taken my session
this.dead = true;
handleInvalidContinuation();
suicide();
}
throw e;
}
this._sendView(uri, k);
// _sendView creates a continuation, the invocation of which
// will return right here: it is used to implement
// <xf:submit continuation="forward">
if (this.dead || cocoon.request == null) {
// this continuation has been invalidated
handleInvalidContinuation();
suicide();
}
this.form.populate(cocoon.environment.objectModel);
if (validator != undefined) {
validator(this);
}
this.form.validate(phase);
if (this.form.violationsAsSortedSet == null ||
this.form.violationsAsSortedSet.size() == 0) {
break;
}
}
}
XForm.prototype._setValidator = function(schNS, schDoc) {
// if validator params are not specified, then
// there is no validation by default
if (schNS == null || schDoc == null ) return null;
var resolver = cocoon.environment;
var schemaSrc = resolver.resolveURI( schDoc );
try {
var is =
Packages.org.apache.cocoon.components.source.SourceUtil.getInputSource(schemaSrc);
var schf =
Packages.org.apache.cocoon.components.validation.SchemaFactory.lookup ( schNS );
var sch = schf.compileSchema ( is );
this.form.setValidator(sch.newValidator());
} finally {
resolver.release(schemaSrc);
}
}
/**
* Sends view to presentation pipeline but doesn't wait for submission
* @param uri [String] presentation pipeline uri
*/
XForm.prototype.finish = function(uri) {
try {
this.form.save(cocoon.environment.objectModel, "request");
} catch (e if (e instanceof java.lang.IllegalStateException)) {
if (cocoon.session.getAttribute(this.id) != null) {
// someone else has taken my session
this.dead = true;
handleInvalidContinuation();
suicide();
}
throw e;
}
cocoon.forwardTo("cocoon://" + cocoon.environment.getURIPrefix() + uri,
this.form.getModel(), null);
delete XForm.forms[this.id]; // delete myself
this.dead = true;
if (this.lastContinuation != null) {
this.lastContinuation.invalidate();
this.lastContinuation = null;
}
}
/**
* Entry point to a flow-based XMLForm application. Replaces the functionality
* of XMLForm actions.
* @param application Name of a JavaScript function that represents the page flow
for a form
* @param id form id
* @param validator_ns XML namespace of validator
* @param validator_doc validator document
* @param scope
*/
function xmlForm(application, id, validator_ns, validator_doc, scope) {
if (cocoon.request == null) {
handleInvalidContinuation("");
return;
}
function getCommand() {
var enum_ = cocoon.request.parameterNames;
var command = undefined;
while (enum_.hasMoreElements()) {
var paramName = enum_.nextElement();
// search for the command
if
(paramName.startsWith(Packages.org.apache.cocoon.Constants.ACTION_PARAM_PREFIX)) {
command =
paramName.substring(Packages.org.apache.cocoon.Constants.ACTION_PARAM_PREFIX.length(),
paramName.length());
break;
}
}
// command encodes the continuation id for "back" or "next" actions
return command;
}
var command = getCommand();
if (command != undefined) {
var xform = XForm.forms[id];
if (xform != undefined) {
// invoke a continuation
var continuationsMgr =
cocoon.componentManager.lookup(Packages.org.apache.cocoon.components.flow.ContinuationsManager.ROLE);
var wk = continuationsMgr.lookupWebContinuation(command);
cocoon.componentManager.release(continuationsMgr);
if (wk != null) {
var jswk = wk.userObject;
xform.form.clearViolations();
jswk.continuation(jswk);
}
}
handleInvalidContinuation(command);
return;
}
// Just start a new instance of the application
cocoon.session.removeAttribute(id);
var args = new Array(arguments.length - 4 + 1);
args[0] = new XForm(id, validator_ns, validator_doc, scope);
for (var i = 4; i < arguments.length; i++) {
args[i-3] = arguments[i];
}
this[application].apply(this, args);
}