You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by vg...@apache.org on 2004/09/30 05:06:12 UTC

svn commit: rev 47529 - in cocoon/branches/BRANCH_2_1_X: . src/java/org/apache/cocoon/components/flow/javascript/fom src/test/anteater

Author: vgritsenko
Date: Wed Sep 29 20:06:12 2004
New Revision: 47529

Added:
   cocoon/branches/BRANCH_2_1_X/src/test/anteater/flowscriptRecursive.xml
      - copied, changed from rev 47523, cocoon/branches/BRANCH_2_1_X/src/test/anteater/flowscriptReload.xml
Modified:
   cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/flow/javascript/fom/FOM_JavaScriptInterpreter.java
   cocoon/branches/BRANCH_2_1_X/src/test/anteater/flowscriptReload.xml
   cocoon/branches/BRANCH_2_1_X/status.xml
Log:
Allow recursive Flow invocations with processPipelineTo.


Modified: cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/flow/javascript/fom/FOM_JavaScriptInterpreter.java
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/flow/javascript/fom/FOM_JavaScriptInterpreter.java	(original)
+++ cocoon/branches/BRANCH_2_1_X/src/java/org/apache/cocoon/components/flow/javascript/fom/FOM_JavaScriptInterpreter.java	Wed Sep 29 20:06:12 2004
@@ -84,10 +84,9 @@
  * @version CVS $Id$
  */
 public class FOM_JavaScriptInterpreter extends CompilingInterpreter
-    implements Configurable, Initializable {
+        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,
@@ -96,9 +95,9 @@
     private final static String LAST_EXEC_TIME = "__PRIVATE_LAST_EXEC_TIME__";
 
     /**
-     * Key for storing a JavaScript global scope object in the Cocoon session
+     * Prefix for session/request attribute storing JavaScript global scope object.
      */
-    public static final String USER_GLOBAL_SCOPE = "FOM JavaScript GLOBAL SCOPE";
+    public static final String USER_GLOBAL_SCOPE = "FOM JavaScript GLOBAL SCOPE/";
 
     // This is the only optimization level that supports continuations
     // in the Christoper Oliver's Rhino JavaScript implementation
@@ -338,80 +337,73 @@
 
     /**
      * Returns the JavaScript scope, a Scriptable object, from the user
-     * session instance. Each sitemap can have a scope associated with it.
+     * session instance. Each interpreter instance can have a scope
+     * associated with it.
      *
-     * @return a <code>Scriptable</code> value
+     * @return a <code>ThreadScope</code> value
      */
     private ThreadScope getSessionScope() throws Exception {
-        Request request = ContextHelper.getRequest(this.avalonContext);
+        final String scopeID = USER_GLOBAL_SCOPE + getInterpreterID();
+        final Request request = ContextHelper.getRequest(this.avalonContext);
+
         ThreadScope scope = null;
+
+        // Get/create the scope attached to the current context
         Session session = request.getSession(false);
         if (session != null) {
-            HashMap userScopes =
-                    (HashMap)session.getAttribute(USER_GLOBAL_SCOPE);
-            if (userScopes != null) {
-                // Get the scope attached to the current context
-                scope = (ThreadScope)userScopes.get(getInterpreterID());
-            }
+            scope = (ThreadScope) session.getAttribute(scopeID);
+        } else {
+            scope = (ThreadScope) request.getAttribute(scopeID);
         }
+
         if (scope == null) {
             scope = createThreadScope();
+            // Save scope in the request early to allow recursive Flow calls
+            request.setAttribute(scopeID, scope);
         }
-        return scope;
-    }
 
-    void updateSession(Scriptable scope) throws Exception {
-        ThreadScope thrScope = (ThreadScope)scope;
-        if (thrScope.useSession) {
-            setSessionScope(scope);
-        }
+        return scope;
     }
 
     /**
-     * Associates a JavaScript scope, a Scriptable object, with the
-     * directory path of the current sitemap, as resolved by the
-     * source resolver.
+     * Associates a JavaScript scope, a Scriptable object, with
+     * {@link #getInterpreterID identifier} of this {@link Interpreter}
+     * instance.
      *
-     * @param scope a <code>Scriptable</code> value
+     * @param scope a <code>ThreadScope</code> value
      */
-    private Scriptable setSessionScope(Scriptable scope) throws Exception {
-        Request request = ContextHelper.getRequest(this.avalonContext);
-
-        // FIXME: Where "session scope" should go when session is invalidated?
-        try {
-            Session session = request.getSession(true);
-
-            HashMap userScopes = (HashMap)session.getAttribute(USER_GLOBAL_SCOPE);
-            if (userScopes == null) {
-                userScopes = new HashMap();
-                session.setAttribute(USER_GLOBAL_SCOPE, userScopes);
-            }
+    private void setSessionScope(ThreadScope scope) throws Exception {
+        if (scope.useSession) {
+            final String scopeID = USER_GLOBAL_SCOPE + getInterpreterID();
+            final Request request = ContextHelper.getRequest(this.avalonContext);
 
+            // FIXME: Where "session scope" should go when session is invalidated?
             // Attach the scope to the current context
-            userScopes.put(getInterpreterID(), scope);
-        } catch (IllegalStateException e) {
-            // Session might be invalidated already.
-            if (getLogger().isDebugEnabled()) {
-                getLogger().debug("Got '" + e + "' while trying to set session scope.", e);
+            try {
+                Session session = request.getSession(true);
+                session.setAttribute(scopeID, scope);
+            } catch (IllegalStateException e) {
+                // Session might be invalidated already.
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("Got '" + e + "' while trying to set session scope.", e);
+                }
             }
         }
-        return scope;
     }
 
     public static class ThreadScope extends ScriptableObject {
-        static final String[] builtinPackages = {"javax", "org", "com"};
+        private static final String[] BUILTIN_PACKAGES = {"javax", "org", "com"};
 
-        ClassLoader classLoader;
+        private ClassLoader classLoader;
 
         /* true if this scope has assigned any global vars */
-        boolean useSession = false;
+        boolean useSession;
 
         public ThreadScope() {
-            final String[] names = { "importClass"};
-
+            final String[] names = { "importClass" };
             try {
-                this.defineFunctionProperties(names, ThreadScope.class,
-                                              ScriptableObject.DONTENUM);
+                defineFunctionProperties(names, ThreadScope.class,
+                                         ScriptableObject.DONTENUM);
             } catch (PropertyException e) {
                 throw new Error();  // should never happen
             }
@@ -422,31 +414,33 @@
         }
 
         public void put(String name, Scriptable start, Object value) {
-            useSession = true;
+            this.useSession = true;
             super.put(name, start, value);
         }
 
         public void put(int index, Scriptable start, Object value) {
-            useSession = true;
+            this.useSession = true;
             super.put(index, start, value);
         }
 
         void reset() {
-            useSession = false;
+            this.useSession = false;
         }
 
-        // Override importClass to allow reloading of classes
-        public static void importClass(Context cx, Scriptable thisObj,
-                                       Object[] args, Function funObj) {
+        /** Override importClass to allow reloading of classes */
+        public static void importClass(Context ctx,
+                                       Scriptable thisObj,
+                                       Object[] args,
+                                       Function funObj) {
             for (int i = 0; i < args.length; i++) {
-                Object cl = args[i];
-                if (!(cl instanceof NativeJavaClass)) {
+                Object clazz = args[i];
+                if (!(clazz instanceof NativeJavaClass)) {
                     throw Context.reportRuntimeError("Not a Java class: " +
-                                                       Context.toString(cl));
+                                                     Context.toString(clazz));
                 }
-                String s = ((NativeJavaClass) cl).getClassObject().getName();
-                String n = s.substring(s.lastIndexOf('.')+1);
-                thisObj.put(n, thisObj, cl);
+                String s = ((NativeJavaClass) clazz).getClassObject().getName();
+                String n = s.substring(s.lastIndexOf('.') + 1);
+                thisObj.put(n, thisObj, clazz);
             }
         }
 
@@ -458,8 +452,8 @@
                 newPackages.setParentScope(this);
                 newPackages.setPrototype(ScriptableObject.getClassPrototype(this, JAVA_PACKAGE));
                 super.put("Packages", this, newPackages);
-                for (int i = 0; i < builtinPackages.length; i++) {
-                    String pkgName = builtinPackages[i];
+                for (int i = 0; i < BUILTIN_PACKAGES.length; i++) {
+                    String pkgName = BUILTIN_PACKAGES[i];
                     Scriptable pkg = new NativeJavaPackage(pkgName, cl);
                     pkg.setParentScope(this);
                     pkg.setPrototype(ScriptableObject.getClassPrototype(this, JAVA_PACKAGE));
@@ -648,13 +642,14 @@
      * @param redirector
      * @exception Exception if an error occurs
      */
-    public void callFunction(String funName, List params,
-                             Redirector redirector) throws Exception {
+    public void callFunction(String funName, List params, Redirector redirector)
+    throws Exception {
         Context context = Context.enter();
         context.setOptimizationLevel(OPTIMIZATION_LEVEL);
         context.setGeneratingDebug(true);
         context.setCompileFunctionsWithDynamicScope(true);
         context.setErrorReporter(errorReporter);
+
         ThreadScope thrScope = getSessionScope();
         synchronized (thrScope) {
             ClassLoader savedClassLoader =
@@ -674,6 +669,7 @@
                             getDebugger().setVisible(true);
                         }
                     }
+
                     int size = (params != null ? params.size() : 0);
                     Object[] funArgs = new Object[size];
                     Scriptable parameters = context.newObject(thrScope);
@@ -686,6 +682,7 @@
                         parameters.put(arg.name, parameters, arg.value);
                     }
                     cocoon.setParameters(parameters);
+
                     Object fun = ScriptableObject.getProperty(thrScope, funName);
                     if (fun == Scriptable.NOT_FOUND) {
                         throw new ResourceNotFoundException("Function \"javascript:" + funName + "()\" not found");
@@ -697,7 +694,7 @@
                                                                                                     ex.getMessage()));
                     Throwable unwrapped = unwrap(ex);
                     if (unwrapped instanceof ProcessingException) {
-                        throw (ProcessingException)unwrapped;
+                        throw (ProcessingException) unwrapped;
                     }
                     throw new CascadingRuntimeException(ee.getMessage(),
                                                         unwrapped);
@@ -713,7 +710,7 @@
                     throw new CascadingRuntimeException(ee.getMessage(), ee);
                 }
             } finally {
-                updateSession(thrScope);
+                setSessionScope(thrScope);
                 if (cocoon != null) {
                     cocoon.popCallContext();
                 }
@@ -800,7 +797,7 @@
                     throw new CascadingRuntimeException(ee.getMessage(), ee);
                 }
             } finally {
-                updateSession(kScope);
+                setSessionScope(kScope);
                 if (cocoon != null) {
                     cocoon.popCallContext();
                 }

Copied: cocoon/branches/BRANCH_2_1_X/src/test/anteater/flowscriptRecursive.xml (from rev 47523, cocoon/branches/BRANCH_2_1_X/src/test/anteater/flowscriptReload.xml)
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/test/anteater/flowscriptReload.xml	(original)
+++ cocoon/branches/BRANCH_2_1_X/src/test/anteater/flowscriptRecursive.xml	Wed Sep 29 20:06:12 2004
@@ -15,58 +15,21 @@
   limitations under the License.
 -->
 
-<project name="flowscriptReload" default="flowscriptReload">
+<project name="flowscriptRecursive" default="flowscriptRecursive">
 
   <group id="default">
     <property name="usetidy" value="true"/>
   </group>
 
   <!-- Check the reloading of the sitemap -->
-  <target name="flowscriptReload">
+  <target name="flowscriptRecursive">
     <property name="test-dir" value="samples/flow/test"/>
-    <property name="url" value="${anteater.env.cocoon}/${test-dir}/showString"/>
+    <property name="url" value="${anteater.env.cocoon}/${test-dir}/factorial?n=5"/>
 
-    <!--+
-        | Copy the flowscript from its source directory to the destination
-        | area, and replace the parameter value with 'abc' 
-        +-->
-
-    <copy file="${anteater.env.src-webapp-dir}/${test-dir}/sendpage.js"
-	  tofile="${anteater.env.deploy-dir}/${test-dir}/sendpage.js"
-	  overwrite="yes">
-      <filterset>
-        <filter token="REPLACEME" value="replaceme-abc"/>
-      </filterset>
-    </copy>
-
-    <!-- make sure change is detected -->
-    <sleep seconds="1"/>
-
-    <httpRequest href="${url}" description="Send original request">
-      <match>
-        <xpath select="html/body/p[1]" pattern=".*replaceme-abc.*"/>
-      </match>
-    </httpRequest>
-
-    <!--+ 
-        | Copy the flowscript from its source directory to the destination
-        | area, and replace the parameter value with '123' 
-        +-->
-
-    <copy file="${anteater.env.src-webapp-dir}/${test-dir}/sendpage.js"
-	  tofile="${anteater.env.deploy-dir}/${test-dir}/sendpage.js"
-	  overwrite="yes">
-      <filterset>
-	    <filter token="REPLACEME" value="replaceme-123"/>
-      </filterset>
-    </copy>
-
-    <!-- make sure change is detected -->
-    <sleep seconds="1"/>
-
-    <httpRequest href="${url}" description="Send next request after flowscript was modified">
+    <httpRequest href="${url}" description="Send Request">
       <match>
-        <xpath select="html/body/p[1]" pattern=".*replaceme-123.*"/>
+        <xpath select="html/body/p[1]" pattern=" 5 "/>
+        <xpath select="html/body/p[2]" pattern="120\.0"/>
       </match>
     </httpRequest>
 

Modified: cocoon/branches/BRANCH_2_1_X/src/test/anteater/flowscriptReload.xml
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/test/anteater/flowscriptReload.xml	(original)
+++ cocoon/branches/BRANCH_2_1_X/src/test/anteater/flowscriptReload.xml	Wed Sep 29 20:06:12 2004
@@ -40,7 +40,7 @@
     </copy>
 
     <!-- make sure change is detected -->
-    <sleep seconds="1"/>
+    <sleep seconds="5"/>
 
     <httpRequest href="${url}" description="Send original request">
       <match>
@@ -62,7 +62,7 @@
     </copy>
 
     <!-- make sure change is detected -->
-    <sleep seconds="1"/>
+    <sleep seconds="5"/>
 
     <httpRequest href="${url}" description="Send next request after flowscript was modified">
       <match>

Modified: cocoon/branches/BRANCH_2_1_X/status.xml
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/status.xml	(original)
+++ cocoon/branches/BRANCH_2_1_X/status.xml	Wed Sep 29 20:06:12 2004
@@ -205,16 +205,19 @@
 
   <changes>
  <release version="@version@" date="@date@">
+   <action dev="VG" type="fix">
+     Allow recursive Flow invocations with processPipelineTo.
+   </action>
    <action dev="SW" type="fix">
-	Forms block: rename <code>fd:on-activate</code> to <code>fd:on-action</code> on
-	<code>fd:row-action</code> and <code>fd:repeater-action</code> for consistency
-	with <code>fd:action</code> and <code>fd:submit</code>.
+     Forms block: rename <code>fd:on-activate</code> to <code>fd:on-action</code> on
+     <code>fd:row-action</code> and <code>fd:repeater-action</code> for consistency
+     with <code>fd:action</code> and <code>fd:submit</code>.
    </action>
    <action dev="CZ" type="update">
      Cache the mime-type of readers and serializers.
    </action>
    <action dev="AG" type="fix" fixes-bug="30372" due-to="Johnson Hsu" due-to-email="johnson@soho.club.tw">
-      The daylight time cause error when timezone is CST. Updated icu4j to 3.0.
+     The daylight time cause error when timezone is CST. Updated icu4j to 3.0.
    </action>
    <action dev="AG" type="fix" fixes-bug="31407" due-to="Mark H. Butler" due-to-email="mark-h.butler@hp.com">
      Upgrading DELI block from version 0.9.8 to x020904.