You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by mr...@apache.org on 2005/02/15 22:10:32 UTC

svn commit: r153960 [2/3] - in struts/flow: ./ branches/ tags/ trunk/ trunk/src/ trunk/src/guess-example/ trunk/src/guess-example/WEB-INF/ trunk/src/java/ trunk/src/java/org/ trunk/src/java/org/apache/ trunk/src/java/org/apache/struts/ trunk/src/java/org/apache/struts/flow/ trunk/src/java/org/apache/struts/flow/core/ trunk/src/wizard-example/ trunk/src/wizard-example/WEB-INF/

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/FlowException.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/FlowException.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/FlowException.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/FlowException.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,122 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation.
+ *
+ *  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.
+ */
+package org.apache.struts.flow.core;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ *  This Exception wraps any exceptions thrown by Flow.
+ */
+public class FlowException extends RuntimeException {
+
+    /**  The Throwable that caused this exception to be thrown.  */
+    private final Throwable throwable;
+
+
+    /**
+     *  Construct a new <code>FlowException</code> instance.
+     *
+     *@param  message  The detail message for this exception.
+     */
+    public FlowException(final String message) {
+        this(message, null);
+    }
+
+
+    /**
+     *  Construct a new <code>FlowException</code> instance.
+     *
+     *@param  message    The detail message for this exception.
+     *@param  throwable  the root cause of the exception
+     */
+    public FlowException(final String message, final Throwable throwable) {
+        super(message);
+        this.throwable = throwable;
+    }
+
+
+    /**
+     *  Retrieve root cause of the exception.
+     *
+     *@return    the root cause
+     */
+    public final Throwable getCause() {
+        return throwable;
+    }
+
+
+    /**
+     *  Creates a new <code>FlowException</code> instance.
+     *
+     *@param  ex  an <code>Exception</code> value
+     */
+    public FlowException(Exception ex) {
+        this(ex.getMessage(), ex);
+    }
+
+
+    /**
+     *  Gets a detailed log of the exception
+     *
+     *@return    The message
+     */
+    public String toString() {
+        StringBuffer s = new StringBuffer();
+        s.append(super.toString());
+        final Throwable t = getCause();
+        if (t != null) {
+            s.append(t.toString());
+        }
+        return s.toString();
+    }
+
+
+    /**  Prints the exception and its cause */
+    public void printStackTrace() {
+        super.printStackTrace();
+        if (getCause() != null) {
+            getCause().printStackTrace();
+        }
+    }
+
+
+    /**
+     *  Prints the exception and its cause
+     *
+     *@param  s  The stream to print to
+     */
+    public void printStackTrace(PrintStream s) {
+        super.printStackTrace(s);
+        if (getCause() != null) {
+            getCause().printStackTrace(s);
+        }
+    }
+
+
+    /**
+     *  Prints the exception and its cause
+     *
+     *@param  s  The writer to print to
+     */
+    public void printStackTrace(PrintWriter s) {
+        super.printStackTrace(s);
+        if (getCause() != null) {
+            getCause().printStackTrace(s);
+        }
+    }
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/FlowException.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/InvalidContinuationException.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/InvalidContinuationException.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/InvalidContinuationException.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/InvalidContinuationException.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,46 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation.
+ *
+ *  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.
+ */
+package org.apache.struts.flow.core;
+
+/**
+ *  This Exception is thrown whenever an invalid continuation is given.
+ *
+ *@author    <a href="mailto:tcollen@neuagency.com">Tony Collen</a>
+ */
+public class InvalidContinuationException extends FlowException {
+
+    /**
+     *  Construct a new <code>InvalidContinuationException</code> instance.
+     *
+     *@param  message  The message of the exception 
+     */
+    public InvalidContinuationException(String message) {
+        super(message, null);
+    }
+
+
+    /**
+     *  Construct a new <code>InvalidContinuationException</code> that
+     *  references a parent Exception.
+     *
+     *@param  message  The message
+     *@param  t        The throwable to wrap
+     */
+    public InvalidContinuationException(String message, Throwable t) {
+        super(message, t);
+    }
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/InvalidContinuationException.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/JSContext.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/JSContext.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/JSContext.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/JSContext.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,262 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation.
+ *
+ *  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.
+ */
+package org.apache.struts.flow.core;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Iterator;
+import java.util.HashMap;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.mozilla.javascript.Wrapper;
+import org.mozilla.javascript.Undefined;
+import org.mozilla.javascript.ScriptableObject;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ScriptRuntime;
+import org.mozilla.javascript.NativeArray;
+import org.mozilla.javascript.Script;
+import org.mozilla.javascript.JavaScriptException;
+
+/**
+ *  JavaScript interface to the chain context and other helpful objects.
+ *
+ *@author     <a href="mailto:ovidiu@cup.hp.com">Ovidiu Predescu</a>
+ *@author     <a href="snoopdave@users.sourceforge.net">Dave Johnson</a>
+ *@since      March 16, 2002
+ *@version    CVS $Id: JSContext.java,v 1.3 2004/11/05 05:12:10 mrdon Exp $
+ */
+public class JSContext extends ScriptableObject {
+    /**  The interpreter */
+    private JavaScriptInterpreter interpreter;
+    /**  The parameters passed by the Flow container */
+    private NativeArray parameters;
+    /**  The continuation manager */
+    private ContinuationsManager continuationsMgr = Factory.getContinuationsManager();
+
+    /**  The thread local storage of the current chain context */
+    private ThreadLocal contextTls = new ThreadLocal();
+
+
+    /**  Constructor for the JSContext object */
+    public JSContext() {
+        super();
+    }
+
+
+    /**
+     *  Gets the class name
+     *
+     *@return    The className value
+     */
+    public String getClassName() {
+        return "context";
+    }
+
+
+    /**
+     *  Sets the parameters used when calling the script
+     *
+     *@param  parameters  The new parameters value
+     */
+    public void setParameters(NativeArray parameters) {
+        this.parameters = parameters;
+    }
+
+
+    /**
+     *  Sets the interpreter
+     *
+     *@param  interpreter  The new interpreter value
+     */
+    public void setInterpreter(JavaScriptInterpreter interpreter) {
+        this.interpreter = interpreter;
+    }
+
+
+    /**
+     *  Sets the chain context
+     *
+     *@param  ctx  The new context value
+     */
+    public void setContext(org.apache.commons.chain.Context ctx) {
+        contextTls.set(ctx);
+    }
+
+
+    /**
+     *  Gets the parameters passed by the Flow container
+     *
+     *@return    The array of parameters
+     */
+    public NativeArray jsGet_parameters() {
+        return parameters;
+    }
+
+
+    /**
+     *  Gets the interpreter
+     *
+     *@return    The interpreter
+     */
+    public JavaScriptInterpreter jsGet_interpreter() {
+        return interpreter;
+    }
+
+
+    /**
+     *  Load the script file specified as argument.
+     *
+     *@param  filename                 a <code>String</code> value
+     *@return                          an <code>Object</code> value
+     *@exception  JavaScriptException  if an error occurs
+     */
+    public Object jsFunction_load(String filename) throws JavaScriptException {
+        org.mozilla.javascript.Context cx =
+                org.mozilla.javascript.Context.getCurrentContext();
+        try {
+            Scriptable scope = getParentScope();
+            Script script = interpreter.compileScript(cx,
+                    (org.apache.commons.chain.Context) contextTls.get(),
+                    filename);
+            return script.exec(cx, scope);
+        } catch (JavaScriptException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new JavaScriptException(e);
+        }
+    }
+
+
+    /**
+     *  Shows the state of this object
+     *
+     *@return    The string state
+     */
+    public String jsFunction_toString() {
+        return "[object " + toString() + "]";
+    }
+
+
+    /**
+     *  Displays all continuations for debugging
+     *
+     *@exception  Exception  If anything goes wrong
+     */
+    public void jsFunction_diplayAllContinuations()
+             throws Exception {
+        continuationsMgr.displayAllContinuations();
+    }
+
+    /**
+     *  Exposes jsobjectToMap to scripts.
+     */
+    public Map jsFunction_jsobjectToMap(Scriptable jsobject) {
+        return jsobjectToMap(jsobject);
+    }
+
+    /**
+     *  Converts a JavaScript object to a HashMap
+     *
+     *@param  jsobject  The object to convert
+     *@return           The Map
+     */
+    public static Map jsobjectToMap(Scriptable jsobject) {
+        HashMap hash = new HashMap();
+        Object[] ids = jsobject.getIds();
+        for (int i = 0; i < ids.length; i++) {
+            String key = ScriptRuntime.toString(ids[i]);
+            Object value = jsobject.get(key, jsobject);
+            if (value == Undefined.instance) {
+                value = null;
+            } else {
+                value = jsobjectToObject(value);
+            }
+            hash.put(key, value);
+        }
+        return hash;
+    }
+
+
+    /**
+     *  Converts a JavaScript object to a Java Object
+     *
+     *@param  obj  The JavaScript object
+     *@return      The Java Object
+     */
+    public static Object jsobjectToObject(Object obj) {
+        // unwrap Scriptable wrappers of real Java objects
+        if (obj instanceof Wrapper) {
+            obj = ((Wrapper) obj).unwrap();
+        } else if (obj == Undefined.instance) {
+            obj = null;
+        }
+        return obj;
+    }
+
+
+    /**
+     *  Gets the parentScope, setting the chain context
+     *
+     *@param  ctx  The chain context
+     *@return      The parentScope value
+     */
+    public Scriptable getParentScope(org.apache.commons.chain.Context ctx) {
+        contextTls.set(ctx);
+        return getParentScope();
+    }
+
+
+    /**
+     *  Gets the value from the chain context
+     *
+     *@param  id  The object id
+     *@return     The object
+     */
+    public Object jsFunction_get(String id) {
+        return ((Map) contextTls.get()).get(id);
+    }
+
+
+    /**
+     *  Gets the chain context
+     *
+     *@return    The chain context
+     */
+    public org.apache.commons.chain.Context jsGet_chainContext() {
+        return (org.apache.commons.chain.Context) contextTls.get();
+    }
+
+
+    /**
+     *  Puts an object in the chain context
+     *
+     *@param  id  The id
+     *@param  o   The object
+     */
+    public void jsFunction_put(String id, Object o) {
+        ((Map) contextTls.get()).put(id, o);
+    }
+
+}
+

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/JSErrorReporter.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/JSErrorReporter.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/JSErrorReporter.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/JSErrorReporter.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,134 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation.
+ *
+ *  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.
+ */
+package org.apache.struts.flow.core;
+
+import org.mozilla.javascript.ErrorReporter;
+import org.mozilla.javascript.EvaluatorException;
+import org.mozilla.javascript.tools.ToolErrorReporter;
+
+/**
+ *  Implements a Rhino JavaScript {@link org.mozilla.javascript.ErrorReporter}.
+ *  Like ToolErrorReporter but logs to supplied logger instead of stdout
+ *
+ *@version    CVS $Id: JSErrorReporter.java,v 1.1.1.1 2004/05/12 00:03:45 mrdon
+ *      Exp $
+ */
+public class JSErrorReporter implements ErrorReporter {
+    private Logger logger;
+
+
+    /**
+     *  Constructor for the JSErrorReporter object
+     *
+     *@param  logger  Description of the Parameter
+     */
+    public JSErrorReporter(Logger logger) {
+        this.logger = logger;
+    }
+
+
+    /**
+     *  Reports an error
+     *
+     *@param  message     The message
+     *@param  sourceName  The source script
+     *@param  line        The line number
+     *@param  lineSrc     The line value
+     *@param  column      The column
+     */
+    public void error(String message,
+            String sourceName, int line,
+            String lineSrc, int column) {
+        String errMsg = getErrorMessage("msg.error", message,
+                sourceName, line, lineSrc, column);
+        logger.error(errMsg);
+    }
+
+
+    /**
+     *  Reports a warning
+     *
+     *@param  message     The message
+     *@param  sourceName  The source script
+     *@param  line        The line number
+     *@param  lineSrc     The line value
+     *@param  column      The column
+     */
+    public void warning(String message, String sourceName, int line,
+            String lineSrc, int column) {
+        String errMsg = getErrorMessage("msg.warning", message,
+                sourceName, line, lineSrc, column);
+        logger.warn(errMsg);
+    }
+
+
+    /**
+     *  Reports a runtime error
+     *
+     *@param  message     The message
+     *@param  sourceName  The source script
+     *@param  line        The line number
+     *@param  lineSrc     The line value
+     *@param  column      The column
+     *@return             Description of the Return Value
+     */
+    public EvaluatorException runtimeError(String message, String sourceName,
+            int line, String lineSrc,
+            int column) {
+        String errMsg = getErrorMessage("msg.error", message,
+                sourceName, line,
+                lineSrc, column);
+        return new EvaluatorException(errMsg);
+    }
+
+
+    /**
+     *  Formats error message
+     *
+     *@param  type        a <code>String</code> value, indicating the error type
+     *      (error or warning)
+     *@param  message     a <code>String</code> value, the error or warning
+     *      message
+     *@param  line        an <code>int</code> value, the original cummulative
+     *      line number
+     *@param  lineSource  a <code>String</code> value, the text of the line in
+     *      the file
+     *@param  column      an <code>int</code> value, the column in <code>lineSource</code>
+     *      where the error appeared
+     *@param  sourceName  The source name
+     *@return             a <code>String</code> value, the aggregated error
+     *      message, with the source file and line number adjusted to the real
+     *      values
+     */
+    String getErrorMessage(String type,
+            String message,
+            String sourceName, int line,
+            String lineSource, int column) {
+        if (line > 0) {
+            if (sourceName != null) {
+                Object[] errArgs = {sourceName, new Integer(line), message};
+                return ToolErrorReporter.getMessage("msg.format3", errArgs);
+            } else {
+                Object[] errArgs = {new Integer(line), message};
+                return ToolErrorReporter.getMessage("msg.format2", errArgs);
+            }
+        } else {
+            Object[] errArgs = {message};
+            return ToolErrorReporter.getMessage("msg.format1", errArgs);
+        }
+    }
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/JSErrorReporter.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/JSGlobal.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/JSGlobal.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/JSGlobal.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/JSGlobal.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,58 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation.
+ *
+ *  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.
+ */
+package org.apache.struts.flow.core;
+
+import org.mozilla.javascript.tools.shell.Global;
+import org.mozilla.javascript.Context;
+
+/**
+ *  Functions and variables in the global JavaScript scope.
+ *
+ *@author     <a href="mailto:ovidiu@cup.hp.com">Ovidiu Predescu</a>
+ *@since      March 17, 2002
+ *@version    CVS $Id: JSGlobal.java,v 1.2 2004/06/03 19:33:29 mrdon Exp $
+ */
+public class JSGlobal extends Global {
+    /**
+     *  Constructor for the JSGlobal object
+     *
+     *@param  cx  The script context
+     */
+    public JSGlobal(Context cx) {
+        super(cx);
+    }
+
+
+    /**
+     *  Gets the class name
+     *
+     *@return    The className value
+     */
+    public String getClassName() {
+        return "Global";
+    }
+
+
+    /**
+     *  Prints a message to the console
+     *
+     *@param  message  The message
+     */
+    public static void print(String message) {
+        System.out.println(message);
+    }
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/JSGlobal.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/JSLog.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/JSLog.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/JSLog.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/JSLog.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,94 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation.
+ *
+ *  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.
+ */
+package org.apache.struts.flow.core;
+
+import org.mozilla.javascript.ScriptableObject;
+
+/**
+ *  JavaScript interface to the log facility.
+ *
+ *@author     <a href="mailto:ovidiu@cup.hp.com">Ovidiu Predescu</a>
+ *@since      March 16, 2002
+ *@version    CVS $Id: JSLog.java,v 1.2 2004/06/03 19:33:29 mrdon Exp $
+ */
+public class JSLog extends ScriptableObject {
+    Logger logger;
+
+
+    /**  Constructor for the JSLog object */
+    public JSLog() { }
+
+
+    /**
+     *  Gets the class name
+     *
+     *@return    The className value
+     */
+    public String getClassName() {
+        return "Log";
+    }
+
+
+    /**
+     *  Sets the logger
+     *
+     *@param  logger  The logger
+     */
+    public void enableLogging(Logger logger) {
+        this.logger = logger;
+    }
+
+
+    /**
+     *  Logs a debug message
+     *
+     *@param  message  Description of the Parameter
+     */
+    public void jsFunction_debug(String message) {
+        logger.debug(message);
+    }
+
+
+    /**
+     *  Logs an info message
+     *
+     *@param  message  Description of the Parameter
+     */
+    public void jsFunction_info(String message) {
+        logger.info(message);
+    }
+
+
+    /**
+     *  Logs a warn message
+     *
+     *@param  message  Description of the Parameter
+     */
+    public void jsFunction_warn(String message) {
+        logger.warn(message);
+    }
+
+
+    /**
+     *  Logs an error message
+     *
+     *@param  message  Description of the Parameter
+     */
+    public void jsFunction_error(String message) {
+        logger.error(message);
+    }
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/JSLog.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/JSWebContinuation.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/JSWebContinuation.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/JSWebContinuation.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/JSWebContinuation.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,157 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation.
+ *
+ *  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.
+ */
+package org.apache.struts.flow.core;
+
+import java.util.List;
+
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.Function;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ScriptableObject;
+import org.mozilla.javascript.Undefined;
+
+/**
+ *  Wraps a web continuation
+ * 
+ *@version    CVS $Id: JSWebContinuation.java,v 1.2 2004/06/02 21:56:54 mrdon
+ *      Exp $
+ */
+public class JSWebContinuation extends ScriptableObject {
+    private WebContinuation wk;
+    private ContinuationsManager continuationsMgr;
+    private JSContext ctx = null;
+
+
+    /**  Constructor for the JSWebContinuation object */
+    public JSWebContinuation() { }
+
+
+    /**
+     *  Gets the class name
+     *
+     *@return    The className value
+     */
+    public String getClassName() {
+        return "WebContinuation";
+    }
+
+
+    /**
+     *  Gets the actual web continuation
+     *
+     *@return    The webContinuation value
+     */
+    public WebContinuation getWebContinuation() {
+        return wk;
+    }
+
+
+    /**
+     *  Creates the JavaScript web continuation
+     *@param  args           Arguments: JSContext context, Object continuation,
+     *      JSWebContinuation parent, Number timeToLive
+     *@param  cx             The script context
+     *@param  ctorObj        The function
+     *@param  inNewExpr      
+     *@return                The new object
+     *@exception  Exception  If anything goes wrong
+     */
+    public static Scriptable jsConstructor(Context cx, Object[] args,
+            Function ctorObj,
+            boolean inNewExpr)
+             throws Exception {
+
+        JSContext ctx = (JSContext) args[0];
+        ContinuationsManager contMgr = Factory.getContinuationsManager();
+
+        Object kont = args[1];
+        JSWebContinuation pjswk = (JSWebContinuation) args[2];
+        WebContinuation pwk = (pjswk == null ? null : pjswk.wk);
+
+        int ttl;
+
+        if (args[3] == Undefined.instance) {
+            ttl = 0;
+        } else {
+            Number timeToLive = (Number) args[3];
+            ttl = (timeToLive == null ? 0 : timeToLive.intValue());
+        }
+
+        JSWebContinuation jswk = new JSWebContinuation();
+        WebContinuation wk = contMgr.createWebContinuation(kont, pwk, ttl, null);
+        wk.setUserObject(jswk);
+
+        jswk.wk = wk;
+        jswk.ctx = ctx;
+        jswk.continuationsMgr = contMgr;
+
+        return jswk;
+    }
+
+
+    /**
+     *  Gets the continuation id
+     *
+     *@return    The id
+     */
+    public String jsGet_id() {
+        return wk.getId();
+    }
+
+
+    /**
+     *  Gets the actual continuation
+     *
+     *@return    The continuation
+     */
+    public Object jsGet_continuation() {
+        return wk.getContinuation();
+    }
+
+
+    /**
+     *  Gets the web continuation
+     *
+     *@return    The web continuation
+     */
+    public Object jsGet_webContinuation() {
+        return wk;
+    }
+
+
+    /**  Invalidates the continuation */
+    public void jsFunction_invalidate() {
+        continuationsMgr.invalidateWebContinuation(wk);
+    }
+
+
+    /**  Displays the continuation */
+    public void jsFunction_display() {
+        wk.display();
+    }
+
+
+    /**
+     *  Gets the JavaScript context
+     *
+     *@return    The context value
+     */
+    public JSContext getContext() {
+        return ctx;
+    }
+
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/JSWebContinuation.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/JavaScriptInterpreter.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/JavaScriptInterpreter.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/JavaScriptInterpreter.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/JavaScriptInterpreter.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,757 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation.
+ *
+ *  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.
+ */
+package org.apache.struts.flow.core;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Iterator;
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.commons.chain.web.servlet.ServletWebContext;
+import javax.servlet.ServletContext;
+
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.EcmaError;
+import org.mozilla.javascript.EvaluatorException;
+import org.mozilla.javascript.Function;
+import org.mozilla.javascript.JavaScriptException;
+import org.mozilla.javascript.NativeArray;
+import org.mozilla.javascript.PropertyException;
+import org.mozilla.javascript.*;
+import org.mozilla.javascript.ScriptRuntime;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ScriptableObject;
+import org.mozilla.javascript.tools.ToolErrorReporter;
+
+/**
+ *  Interface with the JavaScript interpreter.
+ *
+ *@author     <a href="mailto:ovidiu@apache.org">Ovidiu Predescu</a>
+ *@author     <a href="mailto:crafterm@apache.org">Marcus Crafter</a>
+ *@since      March 25, 2002
+ *@version    CVS $Id: JavaScriptInterpreter.java,v 1.3 2004/06/02 21:56:54
+ *      mrdon Exp $
+ */
+public class JavaScriptInterpreter extends CompilingInterpreter {
+
+    /**
+     *  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 session, if
+     *  applicable
+     */
+    public final static String USER_GLOBAL_SCOPE = "JavaScript GLOBAL SCOPE";
+
+    // This is the only optimization level that supports continuations
+    // in the Christoper Oliver's Rhino JavaScript implementation
+    private static int OPTIMIZATION_LEVEL = -2;
+
+    /**
+     *  When was the last time we checked for script modifications. Used only if
+     *  {@link #reloadScripts} is true.
+     */
+    private long lastTimeCheck = System.currentTimeMillis();
+
+    /**  Shared global scope for scripts and other immutable objects */
+    private JSGlobal scope;
+
+    /**
+     *  List of <code>String</code> objects that represent files to be read in
+     *  by the JavaScript interpreter.
+     */
+    private List topLevelScripts = new ArrayList();
+
+    private ArrayList needResolve = new ArrayList();
+
+    /**
+     *  Whether reloading of scripts should be done. Specified through the
+     *  "reload-scripts" attribute in <code>flow.xmap</code>.
+     */
+    private boolean reloadScripts;
+
+    /**
+     *  Interval between two checks for modified script files. Specified through
+     *  the "check-time" XML attribute in <code>flow.xmap</code>.
+     */
+    private long checkTime;
+
+    /**
+     *  JavaScript debugger: there's only one of these: it can debug multiple
+     *  threads executing JS code.
+     */
+    private static org.mozilla.javascript.tools.debugger.Main debugger;
+
+    private JSErrorReporter errorReporter;
+    private boolean enableDebugger = false;
+    private ContinuationsManager continuationsMgr = null;
+    private Scriptable sessionScope = null;
+
+
+    /**  Constructor for the JavaScriptInterpreter object */
+    public JavaScriptInterpreter() {
+        try {
+            continuationsMgr = Factory.getContinuationsManager();
+        } catch (Exception e) {
+            getLogger().error(e);
+        }
+    }
+
+
+    /**
+     *  Gets the logger attribute of the JavaScriptInterpreter object
+     *
+     *@return    The logger value
+     */
+    public Logger getLogger() {
+        return Factory.getLogger();
+    }
+
+
+    /**
+     *  Creates and returns the debugger window
+     *
+     *@return    The debugger value
+     */
+    private static synchronized org.mozilla.javascript.tools.debugger.Main getDebugger() {
+        if (debugger == null) {
+            final org.mozilla.javascript.tools.debugger.Main db
+                     = new org.mozilla.javascript.tools.debugger.Main("Flow Debugger");
+            db.pack();
+            java.awt.Dimension size =
+                    java.awt.Toolkit.getDefaultToolkit().getScreenSize();
+            size.width *= 0.75;
+            size.height *= 0.75;
+            db.setSize(size);
+            db.setExitAction(
+                new Runnable() {
+                    public void run() {
+                        db.setVisible(false);
+                    }
+                });
+            db.setOptimizationLevel(OPTIMIZATION_LEVEL);
+            db.setVisible(true);
+            debugger = db;
+            Context.addContextListener(debugger);
+        }
+        return debugger;
+    }
+
+
+    /**
+     *  Sets whether to enable the debugger
+     *
+     *@param  val  The new debugger value
+     */
+    public void setDebugger(boolean val) {
+        enableDebugger = val;
+    }
+
+
+    /**
+     *  Sets the interval between when the script should be looked at to see if
+     *  it needs to be reloaded
+     *
+     *@param  time  The interval time in milliseconds
+     */
+    public void setCheckTime(long time) {
+        checkTime = time;
+    }
+
+
+    /**
+     *  Sets whether to try to reload modified scripts or not
+     *
+     *@param  val  True to reload
+     */
+    public void setReloadScripts(boolean val) {
+        reloadScripts = val;
+    }
+
+
+    /**
+     *  Initialize the global scope
+     *
+     *@exception  FlowException  If anything goes wrong
+     */
+    public void initialize() throws FlowException {
+        if (enableDebugger) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Flow debugger enabled, creating");
+            }
+            getDebugger().doBreak();
+        }
+        Context context = Context.enter();
+        context.setOptimizationLevel(OPTIMIZATION_LEVEL);
+        context.setCompileFunctionsWithDynamicScope(true);
+        context.setGeneratingDebug(true);
+
+        try {
+            scope = new JSGlobal(context);
+
+            // Register some handy classes with JavaScript, so we can make
+            // use of them from the flow layer.
+            initScope(context, scope);
+
+            errorReporter = new JSErrorReporter(getLogger());
+        } catch (Exception e) {
+            Context.exit();
+            throw new FlowException(e);
+        }
+    }
+
+
+    /**
+     *  Initialize the global scope
+     *
+     *@param  context                        The context
+     *@param  scope                          The scope to initialize
+     *@exception  IllegalAccessException     If anything goes wrong
+     *@exception  PropertyException          If anything goes wrong
+     *@exception  InstantiationException     If anything goes wrong
+     *@exception  InvocationTargetException  If anything goes wrong
+     *@exception  NotAFunctionException      If anything goes wrong
+     *@exception  ClassDefinitionException   If anything goes wrong
+     *@exception  JavaScriptException        If anything goes wrong
+     */
+    protected void initScope(Context context, JSGlobal scope) throws IllegalAccessException,
+            PropertyException, InstantiationException, InvocationTargetException, NotAFunctionException,
+            ClassDefinitionException, JavaScriptException {
+        // Access to the log
+        ScriptableObject.defineClass(scope, JSLog.class);
+
+        // Wrapper for WebContinuation
+        ScriptableObject.defineClass(scope, JSWebContinuation.class);
+
+        // Wrapper for commons-chain context
+        ScriptableObject.defineClass(scope, JSContext.class);
+
+        // Define some functions on the top level scope
+        String[] names = {"print"};
+        try {
+            scope.defineFunctionProperties(names, JSGlobal.class,
+                    ScriptableObject.DONTENUM);
+        } catch (PropertyException e) {
+            throw new Error(e.getMessage());
+        }
+
+        // Define some global variables in JavaScript
+        Object args[] = {};
+        Scriptable log = context.newObject(scope, "Log", args);
+        ((JSLog) log).enableLogging(getLogger());
+        scope.put("log", scope, log);
+    }
+
+
+    /**
+     *  Compile filename as JavaScript code
+     *
+     *@param  cx               Rhino context
+     *@param  source           The source file
+     *@return                  compiled script
+     *@exception  IOException  If anything goes wrong
+     */
+
+    public Script compileScript(Context cx,
+            File source) throws IOException {
+
+        synchronized (compiledScripts) {
+            ScriptSourceEntry entry =
+                    (ScriptSourceEntry) compiledScripts.get(source.getAbsolutePath());
+            Script compiledScript = null;
+            if (entry == null) {
+                compiledScripts.put(source.getAbsolutePath(),
+                        entry = new ScriptSourceEntry(source));
+            }
+            compiledScript = entry.getScript(cx, this.scope, false, this);
+            return compiledScript;
+        }
+    }
+
+
+    /**
+     *  Compiles the script, resolving the path with the chain context if
+     *  possible.
+     *
+     *@param  cx               The script context
+     *@param  chainCtx         The chain context
+     *@param  pathname         The script path
+     *@return                  The compiled script
+     *@exception  IOException  If the script cannot be accessed
+     */
+    public Script compileScript(Context cx, org.apache.commons.chain.Context chainCtx,
+            String pathname) throws IOException {
+
+        synchronized (compiledScripts) {
+            String path = calculatePath(chainCtx, pathname);
+            File file = new File(path);
+            ScriptSourceEntry entry =
+                    (ScriptSourceEntry) compiledScripts.get(file.getAbsolutePath());
+            Script compiledScript = null;
+            if (entry == null) {
+                compiledScripts.put(file.getAbsolutePath(),
+                        entry = new ScriptSourceEntry(file));
+            }
+            compiledScript = entry.getScript(cx, this.scope, false, this);
+            return compiledScript;
+        }
+    }
+
+
+    /**
+     *  Compile the script.
+     *
+     *@param  cx               The script context
+     *@param  source           The script file
+     *@return                  The compiled script
+     *@exception  IOException  If the script cannot be accessed
+     */
+    protected Script reallyCompileScript(Context cx,
+            File source) throws IOException {
+        Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(source)));
+        Script compiledScript = cx.compileReader(scope, reader,
+                source.getAbsolutePath(),
+                1, null);
+        return compiledScript;
+    }
+
+
+    /**
+     *  Calls a JavaScript function, passing <code>params</code> as its
+     *  arguments.
+     *
+     *@param  funName            a <code>String</code> value
+     *@param  params             a <code>List</code> value
+     *@param  chainCtx           The chain context
+     *@exception  FlowException  If anything goes wrong
+     */
+    public void callFunction(String funName, List params,
+            org.apache.commons.chain.Context chainCtx) throws FlowException {
+        Scriptable thrScope = null;
+        try {
+            thrScope = enterContext(chainCtx);
+
+            Context context = Context.getCurrentContext();
+            if (enableDebugger) {
+                if (!getDebugger().isVisible()) {
+                    // only raise the debugger window if it isn't already visible
+                    getDebugger().setVisible(true);
+                }
+            }
+            int size = (params != null ? params.size() : 0);
+            Object[] funArgs = new Object[size];
+            NativeArray parameters = new NativeArray(size);
+            if (size != 0) {
+                for (int i = 0; i < size; i++) {
+                    Argument arg = (Argument) params.get(i);
+                    funArgs[i] = arg.getValue();
+                    if (arg.getName() == null) {
+                        parameters.put(null, parameters, arg.getValue());
+                    } else {
+                        parameters.put(arg.getName(), parameters, arg.getValue());
+                    }
+                }
+            }
+            NativeArray funArgsArray = new NativeArray(funArgs);
+
+            Object fun = ScriptableObject.getProperty(thrScope, funName);
+            if (fun == Scriptable.NOT_FOUND) {
+                getLogger().warn("Function '" + funName + "' not found");
+                fun = funName;
+                // this will produce a better error message
+            }
+            Object callFunArgs[] = {fun, funArgsArray};
+            Object callFun = ScriptableObject.getProperty(thrScope, "callFunction");
+            if (callFun == Scriptable.NOT_FOUND) {
+                callFun = "callFunction";
+                // this will produce a better error message
+            }
+            ScriptRuntime.call(context, callFun, thrScope, callFunArgs, thrScope);
+        } catch (PropertyException ex) {
+            throw new FlowException("Unable to define script property", ex);
+        } catch (NotAFunctionException ex) {
+            throw new FlowException("Unable to define script property", ex);
+        } catch (IOException ex) {
+            throw new FlowException("Unable to compile scripts", ex);
+        } catch (JavaScriptException ex) {
+            EvaluatorException ee =
+                    Context.reportRuntimeError(
+                    ToolErrorReporter.getMessage("msg.uncaughtJSException",
+                    ex.getMessage()));
+            throw new FlowException(ee.getMessage(), ex);
+        } catch (EcmaError ee) {
+            String msg = ToolErrorReporter.getMessage(
+                    "msg.uncaughtJSException", ee.toString());
+            if (ee.getSourceName() != null) {
+                Context.reportRuntimeError(msg,
+                        ee.getSourceName(),
+                        ee.getLineNumber(),
+                        ee.getLineSource(),
+                        ee.getColumnNumber());
+            } else {
+                Context.reportRuntimeError(msg);
+            }
+            throw new FlowException(ee.getMessage(), ee);
+        }
+    }
+
+
+    /**
+     *  Handle a continuation, executing the script where the continuation left
+     *  off.
+     *
+     *@param  id                                The continuation id
+     *@param  params                            The parameters to pass,
+     *      accessible in the JavaScript context variable
+     *@param  chainCtx                          The chain context
+     *@exception  InvalidContinuationException  If anything goes wrong
+     */
+    public void handleContinuation(String id, List params,
+            org.apache.commons.chain.Context chainCtx)
+             throws InvalidContinuationException {
+        WebContinuation wk = continuationsMgr.lookupWebContinuation(id);
+
+        if (wk == null) {
+
+            /*
+             *  Throw an InvalidContinuationException to be handled inside the
+             *  <map:handle-errors> sitemap element.
+             */
+            throw new InvalidContinuationException("The continuation ID " + id + " is invalid.");
+        }
+
+        Context context = Context.enter();
+        context.setOptimizationLevel(OPTIMIZATION_LEVEL);
+        context.setGeneratingDebug(true);
+        context.setCompileFunctionsWithDynamicScope(true);
+
+        // Obtain the JS continuation object from it, and setup the
+        // JSContext object associated in the dynamic scope of the saved
+        // continuation with the environment and context objects.
+        JSWebContinuation jswk = (JSWebContinuation) wk.getUserObject();
+        JSContext ctx = jswk.getContext();
+        final Scriptable kScope = ctx.getParentScope(chainCtx);
+        if (enableDebugger) {
+            getDebugger().setVisible(true);
+        }
+
+        // We can now resume the processing from the state saved by the
+        // continuation object. Setup the JavaScript Context object.
+        Object handleContFunction = kScope.get("handleContinuation", kScope);
+        if (handleContFunction == Scriptable.NOT_FOUND) {
+            throw new RuntimeException("Cannot find 'handleContinuation' "
+                     + "(system.js not loaded?)");
+        }
+
+        Object args[] = {jswk};
+
+        int size = (params != null ? params.size() : 0);
+        NativeArray parameters = new NativeArray(size);
+
+        if (size != 0) {
+            for (int i = 0; i < size; i++) {
+                Argument arg = (Argument) params.get(i);
+                parameters.put(arg.getName(), parameters, arg.getValue());
+            }
+        }
+        ctx.setParameters(parameters);
+
+        try {
+            ((Function) handleContFunction).call(context, kScope, kScope, args);
+        } catch (JavaScriptException ex) {
+            EvaluatorException ee =
+                    Context.reportRuntimeError(ToolErrorReporter.getMessage("msg.uncaughtJSException",
+                    ex.getMessage()));
+            throw new RuntimeException(ee.getMessage(), ee);
+        } catch (EcmaError ee) {
+            String msg = ToolErrorReporter.getMessage("msg.uncaughtJSException", ee.toString());
+            if (ee.getSourceName() != null) {
+                Context.reportRuntimeError(msg,
+                        ee.getSourceName(),
+                        ee.getLineNumber(),
+                        ee.getLineSource(),
+                        ee.getColumnNumber());
+            } else {
+                Context.reportRuntimeError(msg);
+            }
+            throw new RuntimeException(ee.getMessage(), ee);
+        } finally {
+            Context.exit();
+        }
+
+    }
+
+
+    /**
+     *  Returns a new Scriptable object to be used as the global scope when
+     *  running the JavaScript scripts in the context of a request. <p>
+     *
+     *
+     *
+     *@param  chainCtx                   The chain context
+     *@return                            a <code>Scriptable</code> value
+     *@exception  JavaScriptException    If there is a problem compiling the
+     *      JavaScript
+     *@exception  PropertyException      If anything goes wrong
+     *@exception  NotAFunctionException  If the JavaScript function called is
+     *      not a function
+     *@exception  IOException            If anything goes wrong
+     */
+    public Scriptable enterContext(org.apache.commons.chain.Context chainCtx)
+             throws JavaScriptException, PropertyException, NotAFunctionException, IOException {
+        Context context = Context.enter();
+        context.setOptimizationLevel(OPTIMIZATION_LEVEL);
+        context.setGeneratingDebug(true);
+        context.setCompileFunctionsWithDynamicScope(true);
+        context.setErrorReporter(errorReporter);
+        Scriptable thrScope = null;
+
+        // The Cocoon object exported to JavaScript needs to be setup here
+        boolean newScope = false;
+        long lastExecTime = 0;
+        if (thrScope == null) {
+
+            newScope = true;
+
+            thrScope = context.newObject(scope);
+
+            thrScope.setPrototype(scope);
+            // We want 'thrScope' to be a new top-level scope, so set its
+            // parent scope to null. This means that any variables created
+            // by assignments will be properties of "thrScope".
+            thrScope.setParentScope(null);
+
+            setupContext(context, thrScope, chainCtx);
+
+            ((ScriptableObject) thrScope).defineProperty(LAST_EXEC_TIME,
+                    new Long(0),
+                    ScriptableObject.DONTENUM |
+                    ScriptableObject.PERMANENT);
+
+        } else {
+            lastExecTime = ((Long) thrScope.get(LAST_EXEC_TIME,
+                    thrScope)).longValue();
+
+        }
+
+        // Check if we need to compile and/or execute scripts
+        synchronized (compiledScripts) {
+            List execList = new ArrayList();
+            boolean needsRefresh = false;
+            if (reloadScripts) {
+                long now = System.currentTimeMillis();
+                if (now >= lastTimeCheck + checkTime) {
+                    needsRefresh = true;
+                }
+                lastTimeCheck = now;
+            }
+            // If we've never executed scripts in this scope or
+            // if reloadScripts is true and the check interval has expired
+            // or if new scripts have been specified in the sitemap,
+            // then create a list of scripts to compile/execute
+            if (lastExecTime == 0 || needsRefresh || needResolve.size() > 0) {
+                for (Iterator i = needResolve.iterator(); i.hasNext(); ) {
+                    topLevelScripts.add(calculatePath(chainCtx, (String) i.next()));
+                }
+                if (!newScope && !needsRefresh) {
+                    execList.addAll(needResolve);
+                } else {
+                    execList.addAll(topLevelScripts);
+                }
+                needResolve.clear();
+            }
+            thrScope.put(LAST_EXEC_TIME, thrScope,
+                    new Long(System.currentTimeMillis()));
+            // Compile all the scripts first. That way you can set breakpoints
+            // in the debugger before they execute.
+            for (int i = 0, size = execList.size(); i < size; i++) {
+                String sourceURI = (String) execList.get(i);
+                ScriptSourceEntry entry =
+                        (ScriptSourceEntry) compiledScripts.get(sourceURI);
+                if (entry == null) {
+                    File src = new File(sourceURI);
+                    entry = new ScriptSourceEntry(src);
+                    compiledScripts.put(sourceURI, entry);
+                }
+                // Compile the script if necessary
+                entry.getScript(context, this.scope, needsRefresh, this);
+            }
+            // Execute the scripts if necessary
+            for (int i = 0, size = execList.size(); i < size; i++) {
+                String sourceURI = (String) execList.get(i);
+                ScriptSourceEntry entry =
+                        (ScriptSourceEntry) compiledScripts.get(sourceURI);
+                long lastMod = entry.getSource().lastModified();
+                Script script = entry.getScript(context, this.scope, false, this);
+                if (lastExecTime == 0 || lastMod > lastExecTime) {
+                    script.exec(context, thrScope);
+                }
+            }
+        }
+        return thrScope;
+    }
+
+
+    /**
+     *  Setups up the context object fronting the chain context
+     *
+     *@param  context                    The script context
+     *@param  thrScope                   The script scope
+     *@param  chainCtx                   The chain context
+     *@exception  PropertyException      If anything goes wrong
+     *@exception  NotAFunctionException  If anything goes wrong
+     *@exception  JavaScriptException    If anything goes wrong
+     */
+    protected void setupContext(Context context, Scriptable thrScope,
+            org.apache.commons.chain.Context chainCtx)
+             throws PropertyException, NotAFunctionException, JavaScriptException {
+
+        // Put in the thread scope the context object, which gives access
+        // to the interpreter object and the chain context
+        Object args[] = {};
+        JSContext ctx = (JSContext) context.newObject(
+                thrScope, "context", args);
+        ctx.setInterpreter(this);
+        ctx.setContext(chainCtx);
+        ctx.setParentScope(thrScope);
+        thrScope.put("context", thrScope, ctx);
+    }
+
+
+    /**
+     *  Perform any cleanup
+     *
+     *@param  thrScope  The thread scope
+     */
+    public void exitContext(Scriptable thrScope) {
+        Context.exit();
+    }
+
+
+    /**
+     *  Registers a source file with the interpreter. Using this method an
+     *  implementation keeps track of all the script files which are compiled.
+     *  This allows them to reload the script files which get modified on the
+     *  file system. <p>
+     *
+     *  The parsing/compilation of a script file by an interpreter
+     *  retrievesappens in two phases. In the first phase the file's location is
+     *  registered in the <code>needResolve</code> array. The second tries to
+     *  resolve the file location using the chain context.</p> <p>
+     *
+     *  Once a file's location can be resolved, it is removed from the <code>needResolve</code>
+     *  array and placed in the <code>topLevelScripts</code> list.
+     *
+     *@param  source  the location of the script
+     */
+    public void register(String source) {
+        synchronized (this) {
+            needResolve.add(source);
+        }
+    }
+
+
+    /**
+     *  Determines an absolute path to the path name. If the chain context is an
+     *  instance of <code>ServletWebContext</code>, the path is first resolved
+     *  against the <code>ServletContext</code>. If not, the path is also tested
+     *  for being an absolute path already, and if not, tested to see if it is
+     *  in the classpath. If either the path is in the <code>ServletContext</code>
+     *  or in the classpath, a temp file is created and the path to it is
+     *  returned.
+     *
+     *@param  ctx              The chain context
+     *@param  pathname         The script path
+     *@return                  The absolute path to the script file
+     *@exception  IOException  If anything goes wrong
+     */
+    private String calculatePath(org.apache.commons.chain.Context ctx, String pathname)
+             throws IOException {
+
+        InputStream is = null;
+        File tmpdir = null;
+
+        if (ctx instanceof ServletWebContext) {
+            ServletContext context = ((ServletWebContext) ctx).getContext();
+
+            // Can we access the file in the servlet directory?
+            String path = context.getRealPath(pathname);
+            if (path != null) {
+                File file = new File(path);
+                if (file.exists()) {
+                    return (path);
+                }
+            }
+
+            // Determine the servlet temp directory;
+            tmpdir = (File) context.getAttribute
+                    ("javax.servlet.context.tempdir");
+
+            // Try to locate the file in the servlet context
+            is = context.getResourceAsStream(pathname);
+        } else {
+
+            // Set the temp directory
+            tmpdir = new File(System.getProperty("java.io.tmpdir"));
+        }
+
+        // Check to see if the tmp file exists
+        File tmpfile = new File(tmpdir, pathname);
+        if (tmpfile.exists()) {
+            return (tmpfile.getAbsolutePath());
+        }
+
+        // Check to see if the path name is absolute
+        File file = new File(pathname);
+        if (is != null && file.exists()) {
+            return (file.getAbsolutePath());
+        }
+
+        // Try to locate the file on the classpath
+        if (is == null) {
+            is = getClass().getResourceAsStream(pathname);
+        }
+
+        // If no source stream is able to be located
+        if (is == null) {
+            throw new IOException("Unable to load resource:" + pathname);
+        }
+
+        // Read from the source stream and create a tmp file
+        BufferedInputStream bis = new BufferedInputStream(is, 1024);
+        FileOutputStream os =
+                new FileOutputStream(tmpfile);
+        BufferedOutputStream bos = new BufferedOutputStream(os, 1024);
+        byte buffer[] = new byte[1024];
+        while (true) {
+            int n = bis.read(buffer);
+            if (n <= 0) {
+                break;
+            }
+            bos.write(buffer, 0, n);
+        }
+        bos.close();
+        bis.close();
+        return (tmpfile.getAbsolutePath());
+    }
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/JavaScriptInterpreter.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/Logger.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/Logger.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/Logger.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/Logger.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,82 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation.
+ *
+ *  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.
+ */
+package org.apache.struts.flow.core;
+
+/**
+ *  Simple logger. Can be extended to hook into any logging system, but by
+ *  default, prints messages to the console.
+ */
+public class Logger {
+
+    /**
+     *  Logs an error
+     *
+     *@param  msg  The message
+     */
+    public void error(String msg) {
+        System.out.println("JS-ERROR: " + msg);
+    }
+
+
+    /**
+     *  Logs a warning
+     *
+     *@param  msg  The message
+     */
+    public void warn(String msg) {
+        System.out.println("JS-WARNING: " + msg);
+    }
+
+
+    /**
+     *  Logs an info message
+     *
+     *@param  msg  The message
+     */
+    public void info(String msg) {
+        System.out.println("JS-INFO: " + msg);
+    }
+
+
+    /**
+     *  Logs a debugging message
+     *
+     *@param  msg  The message
+     */
+    public void debug(String msg) {
+        System.out.println("JS-DEBUG: " + msg);
+    }
+
+
+    /**
+     *  Gets whether debug is enabled
+     *
+     *@return    True if enabled
+     */
+    public boolean isDebugEnabled() {
+        return true;
+    }
+
+
+    /**
+     *  Prints an exception
+     *
+     *@param  e  The exception
+     */
+    public void error(Exception e) {
+        e.printStackTrace();
+    }
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/Logger.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableMap.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableMap.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableMap.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableMap.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,267 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation.
+ *
+ *  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.
+ */
+package org.apache.struts.flow.core;
+
+import org.mozilla.javascript.NativeJavaObject;
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.Wrapper;
+
+import java.util.Map;
+import java.util.Iterator;
+
+/**
+ *  Wrap a java.util.Map for JavaScript. Borrowed from Cocoon.
+ *
+ *@version    CVS $Id: ScriptableMap.java,v 1.1.1.1 2004/05/12 00:03:45 mrdon
+ *      Exp $
+ */
+public class ScriptableMap implements Scriptable, Wrapper {
+
+    private Map map;
+    private Scriptable prototype, parent;
+
+
+    /**  Constructor for the ScriptableMap object */
+    public ScriptableMap() { }
+
+
+    /**
+     *  Constructor for the ScriptableMap object
+     *
+     *@param  map  The map to wrap
+     */
+    public ScriptableMap(Map map) {
+        this(map, false);
+    }
+    
+    /**
+     *  Constructor for the ScriptableMap object
+     *
+     *@param  map  The map to wrap
+     *@param  deep Whether to recursively wrap contained Maps
+     */
+    public ScriptableMap(Map map, boolean deep) {
+        this.map = map;
+        if (deep) {
+            Map.Entry entry;
+            for (Iterator i = map.entrySet().iterator(); i.hasNext(); ) {
+                entry = (Map.Entry)i.next();
+                if (entry.getValue() instanceof Map) {
+                    entry.setValue(new ScriptableMap((Map)entry.getValue(), deep));
+                }
+            }
+        }
+    }
+
+
+    /**
+     *  Gets the class name
+     *
+     *@return    The className value
+     */
+    public String getClassName() {
+        return "Map";
+    }
+
+
+    /**
+     *  Whether the Map contains the key
+     *
+     *@param  name   The key
+     *@param  start  
+     *@return        True if found
+     */
+    public boolean has(String name, Scriptable start) {
+        return this.map.containsKey(name);
+    }
+
+
+    /**
+     *  N/A, no numeric properties
+     *
+     *@param  index  
+     *@param  start  
+     *@return        Always false
+     */
+    public boolean has(int index, Scriptable start) {
+        return false;
+    }
+
+
+    /**
+     *  Gets the value from the map
+     *
+     *@param  name   The key
+     *@param  start  N/A
+     *@return        The value or <code>NOT_FOUND</code>
+     */
+    public Object get(String name, Scriptable start) {
+        if (this.map.containsKey(name)) {
+            return this.map.get(name);
+        }
+
+        return NOT_FOUND;
+    }
+
+
+    /**
+     *  N/A
+     *
+     *@param  index  
+     *@param  start  
+     *@return        Always <code>NOT_FOUND</code>
+     */
+    public Object get(int index, Scriptable start) {
+        return NOT_FOUND;
+    }
+
+
+    /**
+     *  Puts the value in the map
+     *
+     *@param  name   The key
+     *@param  start  
+     *@param  value  The value
+     */
+    public void put(String name, Scriptable start, Object value) {
+        if (value instanceof NativeJavaObject) {
+            value = ((NativeJavaObject) value).unwrap();
+        }
+        map.put(name, value);
+    }
+
+
+    /**
+     *  N/A
+     *
+     *@param  index  
+     *@param  start  
+     *@param  value  
+     */
+    public void put(int index, Scriptable start, Object value) {
+    }
+
+
+    /**
+     *  Removes the key from the map
+     *
+     *@param  id  The key
+     */
+    public void delete(String id) {
+        map.remove(id);
+    }
+
+
+    /**
+     *  N/A
+     *
+     *@param  index  
+     */
+    public void delete(int index) {
+    }
+
+
+    /**
+     *  Gets the prototype 
+     *
+     *@return    The prototype value
+     */
+    public Scriptable getPrototype() {
+        return prototype;
+    }
+
+
+    /**
+     *  Sets the prototype 
+     *
+     *@param  prototype  The new prototype value
+     */
+    public void setPrototype(Scriptable prototype) {
+        this.prototype = prototype;
+    }
+
+
+    /**
+     *  Gets the parentScope
+     *
+     *@return    The parentScope value
+     */
+    public Scriptable getParentScope() {
+        return parent;
+    }
+
+
+    /**
+     *  Sets the parentScope 
+     *
+     *@param  parent  The new parentScope value
+     */
+    public void setParentScope(Scriptable parent) {
+        this.parent = parent;
+    }
+
+
+    /**
+     *  Gets the keys
+     *
+     *@return    The ids value
+     */
+    public Object[] getIds() {
+        return this.map.keySet().toArray();
+    }
+
+
+    /**
+     *  Gets the default value
+     *
+     *@param  typeHint  
+     *@return           The defaultValue value
+     */
+    public Object getDefaultValue(Class typeHint) {
+        return this.map.toString();
+    }
+
+
+    /**
+     *  Whether the prototype has an instance
+     *
+     *@param  value  The instance
+     *@return        True if found
+     */
+    public boolean hasInstance(Scriptable value) {
+        Scriptable proto = value.getPrototype();
+        while (proto != null) {
+            if (proto.equals(this)) {
+                return true;
+            }
+            proto = proto.getPrototype();
+        }
+
+        return false;
+    }
+
+
+    /**
+     *  Returns the actual Map
+     *
+     *@return    The Map
+     */
+    public Object unwrap() {
+        return this.map;
+    }
+
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableMap.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/WebContinuation.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/WebContinuation.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/WebContinuation.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/WebContinuation.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,359 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation.
+ *
+ *  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.
+ */
+package org.apache.struts.flow.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *  Representation of continuations in a Web environment. <p>
+ *
+ *  Because a user may click on the back button of the browser and restart a
+ *  saved computation in a continuation, each <code>WebContinuation</code>
+ *  becomes the parent of a subtree of continuations. <p>
+ *
+ *  If there is no parent <code>WebContinuation</code>, the created continuation
+ *  becomes the root of a tree of <code>WebContinuation</code>s.
+ *
+ *@author     <a href="mailto:ovidiu@cup.hp.com">Ovidiu Predescu</a>
+ *@since      March 19, 2002
+ *@version    CVS $Id: WebContinuation.java,v 1.2 2004/06/02 21:56:54 mrdon Exp
+ *      $
+ */
+public class WebContinuation implements Comparable {
+
+    /**  The continuation this object represents.  */
+    protected Object continuation;
+
+    /**
+     *  The parent <code>WebContinuation</code> from which processing last
+     *  started. If null, there is no parent continuation associated, and this
+     *  is the first one to be created in a processing. In this case this <code>WebContinuation</code>
+     *  instance becomes the root of the tree maintained by the <code>ContinuationsManager</code>
+     *  .
+     *
+     *@see    ContinuationsManager
+     */
+    protected WebContinuation parentContinuation;
+
+    /**
+     *  The children continuations. These are continuations created by resuming
+     *  the processing from the point stored by <code>continuation</code>.
+     */
+    protected List children = new ArrayList();
+
+    /**
+     *  The continuation id used to represent this instance in Web pages.
+     */
+    protected String id;
+
+    /**
+     *  A user definable object. This is present for convenience, to store any
+     *  information associated with this <code>WebContinuation</code> a
+     *  particular implementation might need.
+     */
+    protected Object userObject;
+
+    /**
+     *  When was this continuation accessed last time. Each time the
+     *  continuation is accessed, this time is set to the time of the access.
+     */
+    protected long lastAccessTime;
+
+    /**
+     *  Indicates how long does this continuation will live (in seconds). The
+     *  continuation will be removed once the current time is bigger than <code>lastAccessTime + timeToLive</code>
+     *  .
+     */
+    protected int timeToLive;
+
+    /**
+     *  Holds the <code>ContinuationsDisposer</code> to call when this
+     *  continuation gets invalidated.
+     */
+    protected ContinuationsDisposer disposer;
+
+
+    /**
+     *  Create a <code>WebContinuation</code> object. Saves the object in the
+     *  hash table of continuations maintained by <code>manager</code> (this is
+     *  done as a side effect of obtaining and identifier from it).
+     *
+     *@param  continuation        an <code>Object</code> value
+     *@param  parentContinuation  a <code>WebContinuation</code> value
+     *@param  timeToLive          time this continuation should live
+     *@param  disposer            a <code>ContinuationsDisposer</code> to call
+     *      when this continuation gets invalidated.
+     *@param  id                  Description of the Parameter
+     */
+    WebContinuation(String id,
+            Object continuation,
+            WebContinuation parentContinuation,
+            int timeToLive,
+            ContinuationsDisposer disposer) {
+        this.id = id;
+        this.continuation = continuation;
+        this.parentContinuation = parentContinuation;
+        this.updateLastAccessTime();
+        this.timeToLive = timeToLive;
+        this.disposer = disposer;
+
+        if (parentContinuation != null) {
+            this.parentContinuation.children.add(this);
+        }
+    }
+
+
+    /**
+     *  Return the continuation object.
+     *
+     *@return    an <code>Object</code> value
+     */
+    public Object getContinuation() {
+        updateLastAccessTime();
+        return continuation;
+    }
+
+
+    /**
+     *  Return the ancestor continuation situated <code>level</code>s above the
+     *  current continuation. The current instance is considered to be at level
+     *  0. The parent continuation of the receiving instance at level 1, its
+     *  parent is at level 2 relative to the receiving instance. If <code>level</code>
+     *  is bigger than the depth of the tree, the root of the tree is returned.
+     *
+     *@param  level  an <code>int</code> value
+     *@return        a <code>WebContinuation</code> value
+     */
+    public WebContinuation getContinuation(int level) {
+        if (level <= 0) {
+            updateLastAccessTime();
+            return this;
+        } else if (parentContinuation == null) {
+            return this;
+        } else {
+            return parentContinuation.getContinuation(level - 1);
+        }
+    }
+
+
+    /**
+     *  Return the parent <code>WebContinuation</code>. Equivalent with <code>getContinuation(1)</code>
+     *  .
+     *
+     *@return    a <code>WebContinuation</code> value
+     */
+    public WebContinuation getParentContinuation() {
+        return parentContinuation;
+    }
+
+
+    /**
+     *  Return the children <code>WebContinuation</code> which were created as a
+     *  result of resuming the processing from the current <code>continuation</code>
+     *  .
+     *
+     *@return    a <code>List</code> value
+     */
+    public List getChildren() {
+        return children;
+    }
+
+
+    /**
+     *  Returns the string identifier of this <code>WebContinuation</code>.
+     *
+     *@return    a <code>String</code> value
+     */
+    public String getId() {
+        return id;
+    }
+
+
+    /**
+     *  Returns the last time this <code>WebContinuation</code> was accessed.
+     *
+     *@return    a <code>long</code> value
+     */
+    public long getLastAccessTime() {
+        return lastAccessTime;
+    }
+
+
+    /**
+     *  Returns the the timetolive for this <code>WebContinuation</code>.
+     *
+     *@return    a <code>long</code> value
+     */
+    public long getTimeToLive() {
+        return this.timeToLive;
+    }
+
+
+    /**
+     *  Sets the user object associated with this instance.
+     *
+     *@param  obj  an <code>Object</code> value
+     */
+    public void setUserObject(Object obj) {
+        this.userObject = obj;
+    }
+
+
+    /**
+     *  Obtains the user object associated with this instance.
+     *
+     *@return    an <code>Object</code> value
+     */
+    public Object getUserObject() {
+        return userObject;
+    }
+
+
+    /**
+     *  Obtains the <code>ContinuationsDisposer</code> to call when this
+     *  continuation is invalidated.
+     *
+     *@return    a <code>ContinuationsDisposer</code> instance or null if there
+     *      are no specific clean-up actions required.
+     */
+    ContinuationsDisposer getDisposer() {
+        return this.disposer;
+    }
+
+
+    /**
+     *  Returns the hash code of the associated identifier.
+     *
+     *@return    an <code>int</code> value
+     */
+    public int hashCode() {
+        return id.hashCode();
+    }
+
+
+    /**
+     *  True if the identifiers are the same, false otherwise.
+     *
+     *@param  another  an <code>Object</code> value
+     *@return          a <code>boolean</code> value
+     */
+    public boolean equals(Object another) {
+        if (another instanceof WebContinuation) {
+            return id.equals(((WebContinuation) another).id);
+        }
+        return false;
+    }
+
+
+    /**
+     *  Compares the expiration time of this instance with that of the
+     *  WebContinuation passed as argument. <p>
+     *
+     *  <b>Note:</b> this class has a natural ordering that is inconsistent with
+     *  <code>equals</code>.</p> .
+     *
+     *@param  other  an <code>Object</code> value, which should be a <code>WebContinuation</code>
+     *      instance
+     *@return        an <code>int</code> value
+     */
+    public int compareTo(Object other) {
+        WebContinuation wk = (WebContinuation) other;
+        return (int) ((lastAccessTime + timeToLive)
+                 - (wk.lastAccessTime + wk.timeToLive));
+    }
+
+
+    /**
+     *  Debugging method. <p>
+     *
+     *  Assumes the receiving instance as the root of a tree and displays the
+     *  tree of continuations.
+     */
+    public void display() {
+        getLogger().debug("\nWK: Tree" + display(0));
+    }
+
+
+    /**
+     *  Debugging method. <p>
+     *
+     *  Displays the receiving instance as if it is at the <code>indent</code>
+     *  depth in the tree of continuations. Each level is indented 2 spaces.
+     *
+     *@param  depth  an <code>int</code> value
+     *@return        Description of the Return Value
+     */
+    protected String display(int depth) {
+        StringBuffer tree = new StringBuffer("\n");
+        for (int i = 0; i < depth; i++) {
+            tree.append("  ");
+        }
+
+        tree.append("WK: WebContinuation ")
+                .append(id)
+                .append(" ExpireTime [");
+
+        if ((lastAccessTime + timeToLive) < System.currentTimeMillis()) {
+            tree.append("Expired");
+        } else {
+            tree.append(lastAccessTime + timeToLive);
+        }
+
+        tree.append("]");
+
+        // REVISIT: is this needed for some reason?
+        // System.out.print(spaces); System.out.println("WebContinuation " + id);
+
+        int size = children.size();
+        depth++;
+
+        for (int i = 0; i < size; i++) {
+            tree.append(((WebContinuation) children.get(i)).display(depth));
+        }
+
+        return tree.toString();
+    }
+
+
+    /**  Update the continuation in the  */
+    protected void updateLastAccessTime() {
+        lastAccessTime = System.currentTimeMillis();
+    }
+    
+    /**
+     *  Gets the logger 
+     *
+     *@return    The logger value
+     */
+    public Logger getLogger() {
+        return Factory.getLogger();
+    }
+
+
+    /**
+     *  Determines whether this continuation has expired
+     *
+     *@return    a <code>boolean</code> value
+     */
+    public boolean hasExpired() {
+        long currentTime = System.currentTimeMillis();
+        long expireTime = this.getLastAccessTime() + this.timeToLive;
+
+        return (currentTime > expireTime);
+    }
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/WebContinuation.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/package.html
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/package.html?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/package.html (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/package.html Tue Feb 15 13:09:29 2005
@@ -0,0 +1,17 @@
+<html>
+<head>
+    <title>Flow Implementation</title>
+</head>
+<body>
+    <p>Extracted from <a href="http://cocoon.apache.org">Apache Cocoon</a>, this Flow implementation uses  
+    Mozilla's Rhino JavaScript interpreter, and <a href="http://jakarta.apache.org/commons/sandbox/chain">commons-chain</a> to enable continuations-based processing.  The use of    this library is not limited to the Servlet API or even web applications, although they generally need the     forrested continuation trees most, which allow the Flow to properly handle starting previous continuations like    in the case of the browser back button.
+    </p>
+    <p>
+    In Rhino a continuation is a JavaScript object that represents a snapshot of the state of an executing Rhino script -- i.e the current call-stack -- including each call-frame's program counter and local variables.  Captured continuation does not save the state of the variables, but rather pointers to the variables. Example: two continuations will share one instance of the local variable declared in the function, if those two continuations were created during execution of the same call of this function.
+    </p>
+    <p>
+    The term "Continuation" (borrowed from Scheme) is used because it represents the rest of, or the "continuation" of, a program. Each time you call a function, there is an implicit continuation -- the place where the function should return to. A JavaScript Continuation object provides a way to bind that implicit continuation to a name and keep hold of it. If you don't do anything with the named continuation, the program will eventually invoke it anyway when the function returns and passes control to its caller. Now that it's named, however, you could invoke the continuation earlier than normal, or you could invoke it later (after it has already been invoked by the normal control flow). In the early case, the effect is a non-local exit. In the later case, it's more like returning from the same function more than once.
+    </p>
+</body>
+</html>
+    

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/package.html
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/package.html
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/package.html?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/package.html (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/package.html Tue Feb 15 13:09:29 2005
@@ -0,0 +1,9 @@
+<html>
+<head>
+    <title>Struts Flow</title>
+</head>
+<body>
+    This package adapts the generic Flow implementation to Struts, making it possible to write Struts actions in Flow script.  JavaScript methods that provide access to common web and Struts objects are provided to each script. 
+</body>
+</html>
+    

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/package.html
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/struts.js
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/struts.js?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/struts.js (added)
+++ struts/flow/trunk/src/java/struts.js Tue Feb 15 13:09:29 2005
@@ -0,0 +1,66 @@
+importClass(Packages.net.sf.struts.flow.Constants);
+importPackage(Packages.flow);
+
+function getRequestParams() {
+    return new ScriptableMap(context.chainContext.getParam());
+}
+
+function getRequestParamValues() {
+    return new ScriptableMap(context.chainContext.getParamValues());
+}
+
+function getRequestScope() {
+    return new ScriptableMap(context.chainContext.getRequestScope());
+}
+
+function getSessionScope() {
+    return new ScriptableMap(context.chainContext.getSessionScope());
+}
+
+function getApplicationScope() {
+    return new ScriptableMap(context.chainContext.getApplicationScope());
+}
+
+function getForm() {
+    return context.get(Constants.ACTION_FORM_KEY);
+}
+
+function getMessage(key) {
+    res = context.get(Constants.MESSAGE_RESOURCES_KEY);
+    return res.getMessage(key);
+}
+
+function getMapping() {
+    return context.get(Constants.ACTION_CONFIG_KEY);
+}
+
+function isCancelled() {
+    action = context.get(Constants.ACTION_KEY);
+    return action.isCancelled(context.chainContext.getRequest());
+}
+
+function isTokenValid() {
+    action = context.get(Constants.ACTION_KEY);
+    return action.isTokenValid(context.chainContext.getRequest());
+}
+
+function resetToken() {
+    action = context.get(Constants.ACTION_KEY);
+    return action.resetToken(context.chainContext.getRequest());
+}
+
+function saveErrors(errors) {
+    action = context.get(Constants.ACTION_KEY);
+    return action.saveErrors(context.chainContext.getRequest(), errors);
+}
+
+function saveMessages(msgs) {
+    action = context.get(Constants.ACTION_KEY);
+    return action.saveMessages(context.chainContext.getRequest(), msgs);
+}
+
+function saveToken() {
+    action = context.get(Constants.ACTION_KEY);
+    return action.saveToken(context.chainContext.getRequest());
+}
+

Propchange: struts/flow/trunk/src/java/struts.js
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/system.js
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/system.js?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/system.js (added)
+++ struts/flow/trunk/src/java/system.js Tue Feb 15 13:09:29 2005
@@ -0,0 +1,57 @@
+
+var suicide;
+
+var lastContinuation = null;
+
+function startContinuation(lastWebCont) {
+    var k = new Continuation();
+    
+    // Use default ttl value from continuation manager
+    var timeToLive = 0;
+    var kont = new WebContinuation(context, k, lastWebCont, timeToLive);
+    if (this.rootContinuation == null) {
+        this.rootContinuation = kont;
+    }
+    return kont;
+} 
+
+
+function callFunction(func, args)
+{
+   suicide = new Continuation();
+   return func.apply(this, args);
+}
+
+function forwardAndWait(name, atts)
+{
+   var kont = _forwardAndWait(name, atts);
+   lastContinuation = kont;
+   return kont;
+}
+
+function _forwardAndWait(name, atts)
+{
+   var k = new Continuation();
+   
+   // Use default ttl value from continuation manager
+   var timeToLive = 0;
+   var kont = new WebContinuation(context, k, lastContinuation, timeToLive);
+   
+   context.put(Constants.FORWARD_NAME_KEY, name);
+   context.put(Constants.CONTINUATION_ID_KEY, kont.id);
+   context.put(Constants.BIZ_DATA_KEY, atts);
+   
+   suicide();
+   
+   return kont;
+}
+
+// This function is called to restart a previously saved continuation
+// passed as argument.
+function handleContinuation(kont)
+{
+    kont.continuation(kont);
+}
+
+
+

Propchange: struts/flow/trunk/src/java/system.js
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/wizard-example/WEB-INF/struts-config.xml
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/wizard-example/WEB-INF/struts-config.xml?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/wizard-example/WEB-INF/struts-config.xml (added)
+++ struts/flow/trunk/src/wizard-example/WEB-INF/struts-config.xml Tue Feb 15 13:09:29 2005
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+
+<!DOCTYPE struts-config PUBLIC
+          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
+          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
+
+<struts-config>
+
+
+  <!-- ========== Action Mapping Definitions ============================== -->
+  <action-mappings>
+
+    <action    path="/registration"
+               type="net.sf.struts.flow.FlowAction"
+          className="net.sf.struts.flow.FlowMapping">
+          
+      <set-property property="function" value="main" />
+
+      <forward name="name-form"              path="/name-form.jsp"/>
+      <forward name="hobbies-form"              path="/hobbies-form.jsp"/>
+      <forward name="summary-form"              path="/summary-form.jsp"/>
+    </action>
+ </action-mappings>   
+
+
+  <plug-in className="net.sf.struts.flow.FlowPlugIn">
+    <set-property property="scripts" value="/WEB-INF/wizard-flow.js" />
+    <set-property property="debugger" value="false" />
+    <set-property property="reloadScripts" value="true" />
+    <set-property property="checkTime" value="1" />
+    <set-property property="timeToLive" value="600000" />
+  </plug-in>
+
+
+</struts-config>

Propchange: struts/flow/trunk/src/wizard-example/WEB-INF/struts-config.xml
------------------------------------------------------------------------------
    svn:executable = *



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org