stephan     2004/06/24 09:48:54

  Modified:    src/blocks/javaflow/java/org/apache/cocoon/components/flow/java
                        AbstractContinuable.java
                        ContinuationClassLoader.java JavaInterpreter.java
               
src/blocks/javaflow/java/org/apache/cocoon/components/flow/java/analyser
                        Subroutines.java
               
src/blocks/javaflow/test/org/apache/cocoon/components/flow/java/test
                        JavaFlowTestCase.java JavaFlowTestCase.xtest
                        SimpleFlow.java
               
src/blocks/javaflow/test/org/apache/cocoon/components/flow/javascript
                        JavaScriptFlowTestCase.java
                        JavaScriptFlowTestCase.xtest
  Added:       src/blocks/javaflow/java/org/apache/cocoon/components/flow/java
                        DecompilingVisitor.java
               
src/blocks/javaflow/java/org/apache/cocoon/components/flow/javascript
                        JavaScriptHelper.java JavaScriptInterpreter.java
                        ScriptHelper.java
  Log:
  Using a "ScriptHelper" to encapsulate the instrumented JavaScript interpreter.
  Add a decompiler to debug the bytecode based on Torsten's work.
  The current problem is the usage of "xxx.class", which were
  translated to "Class.forName("..")".
  
  Revision  Changes    Path
  1.6       +16 -1     
cocoon-2.1/src/blocks/javaflow/java/org/apache/cocoon/components/flow/java/AbstractContinuable.java
  
  Index: AbstractContinuable.java
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.1/src/blocks/javaflow/java/org/apache/cocoon/components/flow/java/AbstractContinuable.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- AbstractContinuable.java  23 Jun 2004 09:16:31 -0000      1.5
  +++ AbstractContinuable.java  24 Jun 2004 16:48:53 -0000      1.6
  @@ -16,11 +16,14 @@
   package org.apache.cocoon.components.flow.java;
   
   import org.apache.avalon.framework.CascadingRuntimeException;
  +import org.apache.avalon.framework.context.Context;
   import org.apache.avalon.framework.logger.Logger;
   import org.apache.avalon.framework.parameters.Parameters;
  +import org.apache.avalon.framework.service.ServiceManager;
   import org.apache.cocoon.components.ContextHelper;
   import org.apache.cocoon.components.flow.FlowHelper;
   import org.apache.cocoon.components.flow.util.PipelineUtil;
  +import org.apache.cocoon.environment.Redirector;
   import org.apache.cocoon.environment.Request;
   import org.apache.excalibur.source.SourceUtil;
   
  @@ -44,6 +47,18 @@
     
       public Logger getLogger() {
           return getContext().getLogger();
  +    }
  +    
  +    public Context getAvalonContext() {
  +        return getContext().getAvalonContext();
  +    }
  +
  +    public ServiceManager getServiceManager() {
  +        return getContext().getServiceManager();
  +    }
  + 
  +    public Redirector getRedirector() {
  +        return getContext().getRedirector();
       }
   
       public void sendPageAndWait(String uri) {
  
  
  
  1.11      +68 -13    
cocoon-2.1/src/blocks/javaflow/java/org/apache/cocoon/components/flow/java/ContinuationClassLoader.java
  
  Index: ContinuationClassLoader.java
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.1/src/blocks/javaflow/java/org/apache/cocoon/components/flow/java/ContinuationClassLoader.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- ContinuationClassLoader.java      14 Jun 2004 15:08:35 -0000      1.10
  +++ ContinuationClassLoader.java      24 Jun 2004 16:48:53 -0000      1.11
  @@ -15,6 +15,7 @@
    */
   package org.apache.cocoon.components.flow.java;
   
  +import java.io.FileOutputStream;
   import java.util.*;
   
   import org.apache.bcel.*;
  @@ -57,6 +58,8 @@
   
       private static boolean currentMethodStatic;
       
  +    private boolean debug = false;
  +     
       private List includes = new ArrayList();
   
       public ContinuationClassLoader(ClassLoader parent) {
  @@ -64,6 +67,10 @@
           Repository.setRepository(new ClassLoaderRepository(parent));
       }
       
  +    public void setDebug(boolean debug) {
  +     this.debug = debug;
  +    }
  +    
       public void addIncludeClass(String pattern) {
           
           StringBuffer buffer = new StringBuffer();
  @@ -106,12 +113,16 @@
       protected synchronized Class loadClass(String name, boolean resolve)
               throws ClassNotFoundException {
           // this finds also classes, which are already transformed, via 
findLoadedClass
  +     if (debug)
  +             System.out.println("load class "+name);
           Class c = super.loadClass(name, resolve);
   
           // transform class if class is continuable and not continuation 
capable
           if (isContinuable(c) && 
               (!ContinuationCapable.class.isAssignableFrom(c)) && 
               (!c.isInterface())) {
  +             if (debug)
  +                     System.out.println("instrument class "+name);
               JavaClass clazz = Repository.lookupClass(c);
   
               byte data[] = transform(clazz);
  @@ -127,9 +138,21 @@
       }
   
       private byte[] transform(JavaClass javaclazz) throws 
ClassNotFoundException {
  +     
           // make all methods of java class continuable
           ClassGen clazz = new ClassGen(javaclazz);
           ConstantPoolGen cp = clazz.getConstantPool();
  +        
  +        if (debug) {
  +             try {
  +                FileOutputStream fos = new 
FileOutputStream(javaclazz.getClassName() + ".orig.j");
  +                DecompilingVisitor v = new DecompilingVisitor(javaclazz, 
fos);
  +                v.start();
  +            } catch (Exception e) {
  +                e.printStackTrace();
  +            }
  +        }
  +        
           // vistor to build the frame information
           ExecutionVisitor ev = new ExecutionVisitor();
           ev.setConstantPoolGen(cp);
  @@ -144,11 +167,13 @@
                   // information about every instruction
                   ControlFlowGraph cfg = new ControlFlowGraph(method);
                   
  -                //System.out.println("analyse " + methods[i].getName());
  +                if (debug)
  +                     System.out.println("analyse " + methods[i].getName());
                   analyse(clazz, method, cfg, ev);
                   
                   // add intercepting code
  -                //System.out.println("rewriting " + methods[i].getName());
  +                if (debug)
  +                     System.out.println("rewriting " + methods[i].getName());
                   rewrite(method, cfg);
                   
                   // make last optional check for consistency
  @@ -168,15 +193,25 @@
               }
           }
           
  -        /*byte[] changed = clazz.getJavaClass().getBytes();
  -        try {
  -            java.io.FileOutputStream out = new 
java.io.FileOutputStream(clazz.getClassName() + ".rewritten.class");
  -            out.write(changed);
  -            out.flush();
  -            out.close();
  -        } catch (java.io.IOException ioe) {
  -            ioe.printStackTrace();
  -        }*/
  +        if (debug) {
  +             byte[] changed = clazz.getJavaClass().getBytes();
  +             try {
  +                     FileOutputStream out = new 
FileOutputStream(clazz.getClassName() + ".rewritten.class");
  +                     out.write(changed);
  +                     out.flush();
  +                     out.close();
  +             } catch (java.io.IOException ioe) {
  +                     ioe.printStackTrace();
  +             }
  +             
  +             try {
  +                FileOutputStream fos = new 
FileOutputStream(clazz.getClassName() + ".rewritten.j");
  +                DecompilingVisitor v = new 
DecompilingVisitor(clazz.getJavaClass(), fos);
  +                v.start();
  +            } catch (Exception e) {
  +                e.printStackTrace();
  +            }
  +        }
           
           clazz.addInterface(CONTINUATIONCAPABLE_CLASS);
           return clazz.getJavaClass().getBytes();
  @@ -417,6 +452,8 @@
               insList.insert(InstructionFactory.createLoad(STACK_TYPE, 
method.getMaxLocals()+1));
   
               // test if the continuation should be restored
  +            if (debug)
  +             insList.insert(insFactory.createPrintln("restoring invocation 
"+method));
               insList.insert(new IFEQ(firstIns));
               insList.insert(insFactory.createInvoke(CONTINUATION_CLASS, 
RESTORING_METHOD, Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
               insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, 
method.getMaxLocals()));
  @@ -541,6 +578,8 @@
           boolean skipFirst = returnType.getSize() > 0;
   
           // save stack
  +        if (debug)
  +             insList.append(insFactory.createPrintln("save stack"));
           OperandStack os = frame.getStack();
           for (int i = skipFirst ? 1 : 0; i < os.size(); i++) {
               Type type = os.peek(i);
  @@ -572,15 +611,24 @@
                   insList.append(insFactory.createInvoke(STACK_CLASS, 
getPushMethod(Type.OBJECT), Type.VOID, new Type[]{Type.OBJECT}, 
Constants.INVOKEVIRTUAL));
               }
           }
  +        
           // add isCapturing test
  +        if (debug)
  +             insList.insert(insFactory.createPrintln("capturing invocation 
"+method));
           insList.insert(new IFEQ(handle.getNext()));
  +        
           // test if the continuation should be captured after the invocation
           insList.insert(insFactory.createInvoke(CONTINUATION_CLASS, 
CAPURING_METHOD, Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
           insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, 
method.getMaxLocals()));
  +        
           // test if continuation exists
           insList.insert(new IFNULL(handle.getNext()));
           insList.insert(InstructionFactory.createLoad(CONTINUATION_TYPE, 
method.getMaxLocals()));
  +        
           // save local variables
  +        if (debug)
  +             insList.append(insFactory.createPrintln("save local 
variables"));
  +        
           LocalVariables lvs = frame.getLocals();
           for (int i = 0; i < lvs.maxLocals(); i++) {
               Type type = lvs.get(i);
  @@ -619,7 +667,11 @@
       private InstructionList restoreFrame(MethodGen method, InstructionHandle 
handle,
               InstructionFactory insFactory, Frame frame, ObjectType 
objecttype) {
           InstructionList insList = new InstructionList();
  +        
           // restore local variables
  +        if (debug)
  +             insList.append(insFactory.createPrintln("restore local 
variables"));
  +        
           LocalVariables lvs = frame.getLocals();
           for (int i = lvs.maxLocals() - 1; i >= 0; i--) {
               Type type = lvs.get(i);
  @@ -649,8 +701,11 @@
           InvokeInstruction inv = (InvokeInstruction) handle.getInstruction();
           Type returnType = 
getReturnType(method.getConstantPool().getConstantPool(), inv.getIndex());
           boolean skipFirst = returnType.getSize() > 0;
  -
  +        
           // restore stack
  +        if (debug)
  +             insList.append(insFactory.createPrintln("restore stack"));
  +        
           OperandStack os = frame.getStack();
           for (int i = os.size() - 1; i >= (skipFirst ? 1 : 0); i--) {
               Type type = os.peek(i);
  
  
  
  1.10      +2 -1      
cocoon-2.1/src/blocks/javaflow/java/org/apache/cocoon/components/flow/java/JavaInterpreter.java
  
  Index: JavaInterpreter.java
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.1/src/blocks/javaflow/java/org/apache/cocoon/components/flow/java/JavaInterpreter.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- JavaInterpreter.java      23 Jun 2004 09:16:32 -0000      1.9
  +++ JavaInterpreter.java      24 Jun 2004 16:48:53 -0000      1.10
  @@ -77,6 +77,7 @@
               throw new ConfigurationException(e.getMessage());
           }
           continuationclassloader = new 
ContinuationClassLoader(javascriptclassloader);
  +        
continuationclassloader.setDebug(config.getAttributeAsBoolean("debug", false));
   
           Configuration[] includes = config.getChildren("include");
           for (int i = 0; i < includes.length; i++)
  
  
  
  1.1                  
cocoon-2.1/src/blocks/javaflow/java/org/apache/cocoon/components/flow/java/DecompilingVisitor.java
  
  Index: DecompilingVisitor.java
  ===================================================================
  /*
   * 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.cocoon.components.flow.java;
  
  import java.io.OutputStream;
  import java.io.PrintWriter;
  import java.util.Hashtable;
  
  import org.apache.bcel.Constants;
  import org.apache.bcel.classfile.Attribute;
  import org.apache.bcel.classfile.Code;
  import org.apache.bcel.classfile.ConstantValue;
  import org.apache.bcel.classfile.Deprecated;
  import org.apache.bcel.classfile.ExceptionTable;
  import org.apache.bcel.classfile.Field;
  import org.apache.bcel.classfile.JavaClass;
  import org.apache.bcel.classfile.Method;
  import org.apache.bcel.classfile.Synthetic;
  import org.apache.bcel.classfile.Utility;
  import org.apache.bcel.generic.BranchInstruction;
  import org.apache.bcel.generic.CodeExceptionGen;
  import org.apache.bcel.generic.ConstantPoolGen;
  import org.apache.bcel.generic.Instruction;
  import org.apache.bcel.generic.InstructionHandle;
  import org.apache.bcel.generic.InstructionList;
  import org.apache.bcel.generic.LocalVariableGen;
  import org.apache.bcel.generic.MethodGen;
  import org.apache.bcel.generic.ObjectType;
  import org.apache.bcel.generic.Select;
  import org.apache.bcel.generic.TABLESWITCH;
  
  public final class DecompilingVisitor extends 
org.apache.bcel.classfile.EmptyVisitor {
        private JavaClass clazz;
        private PrintWriter out;
        private String clazzname;
        private ConstantPoolGen cp;
  
        public DecompilingVisitor(JavaClass clazz, OutputStream out) {
                this.clazz = clazz;
                this.out = new PrintWriter(out);
                clazzname = clazz.getClassName();
                cp = new ConstantPoolGen(clazz.getConstantPool());
        }
  
        public void start() {
                new org.apache.bcel.classfile.DescendingVisitor(clazz, 
this).visit();
                out.close();
        }
  
        public void visitJavaClass(JavaClass clazz) {
  
                out.println("// source " + clazz.getSourceFileName());
                out.println(Utility.accessToString(clazz.getAccessFlags(), 
true) + " "
                                + 
Utility.classOrInterface(clazz.getAccessFlags()) + " "
                                + clazz.getClassName().replace('.', '/'));
                out.println("  extends " + 
clazz.getSuperclassName().replace('.', '/'));
  
                String[] interfaces = clazz.getInterfaceNames();
  
                if (interfaces.length > 0) {
                        out.print("  implements");
                        for (int i = 0; i < interfaces.length; i++)
                                out.print(" " + interfaces[i].replace('.', 
'/'));
                        out.println();
                }
                out.println();
        }
  
        public void visitField(Field field) {
                out.print("  " + Utility.accessToString(field.getAccessFlags()) 
+ " "
                                + field.getName() + " " + field.getSignature());
                if (field.getAttributes().length == 0)
                        out.print("\n");
        }
  
        public void visitConstantValue(ConstantValue cv) {
                out.println(" = " + cv);
        }
  
        private Method _method;
  
        /**
         * Unfortunately Jasmin expects ".end method" after each method. Thus 
we've
         * to check for every of the method's attributes if it's the last one 
and
         * print ".end method" then.
         */
        private final void printEndMethod(Attribute attr) {
                Attribute[] attributes = _method.getAttributes();
  
        }
  
        public void visitDeprecated(Deprecated attribute) {
                printEndMethod(attribute);
        }
  
        public void visitSynthetic(Synthetic attribute) {
                if (_method != null)
                        printEndMethod(attribute);
        }
  
        public void visitMethod(Method method) {
                this._method = method; // Remember for use in subsequent 
visitXXX calls
  
                out.println("\n  " + 
Utility.accessToString(_method.getAccessFlags())
                                + " " + _method.getName() + 
_method.getSignature());
  
        }
  
        public void visitExceptionTable(ExceptionTable e) {
                String[] names = e.getExceptionNames();
                for (int i = 0; i < names.length; i++)
                        out.println("    throws " + names[i].replace('.', '/'));
  
                printEndMethod(e);
        }
  
        private Hashtable map;
  
        public void visitCode(Code code) {
                int label_counter = 0;
  
                MethodGen mg = new MethodGen(_method, clazzname, cp);
                InstructionList il = mg.getInstructionList();
                InstructionHandle[] ihs = il.getInstructionHandles();
  
                LocalVariableGen[] lvs = mg.getLocalVariables();
  
                CodeExceptionGen[] ehs = mg.getExceptionHandlers();
  
                for (int i = 0; i < lvs.length; i++) {
                        LocalVariableGen l = lvs[i];
                        out.println("    // var " + l.getIndex() + " is \"" + 
l.getName()
                                        + "\" " + l.getType().getSignature() + 
" from "
                                        + l.getStart().getPosition() + " to "
                                        + l.getEnd().getPosition());
                }
  
                out.print("\n");
  
                for (int i = 0; i < ihs.length; i++) {
                        InstructionHandle ih = ihs[i];
                        Instruction inst = ih.getInstruction();
  
                        out.print("    " + ih.getPosition());
  
                        if (inst instanceof BranchInstruction) {
                                if (inst instanceof Select) { // Special cases 
LOOKUPSWITCH and
                                                                                
          // TABLESWITCH
                                        Select s = (Select) inst;
                                        int[] matchs = s.getMatchs();
                                        InstructionHandle[] targets = 
s.getTargets();
  
                                        if (s instanceof TABLESWITCH) {
                                                out.println("  tableswitch " + 
matchs[0] + " "
                                                                + 
matchs[matchs.length - 1]);
  
                                                for (int j = 0; j < 
targets.length; j++)
                                                        out.println("        " 
+ targets[j].getPosition());
  
                                        } else { // LOOKUPSWITCH
                                                out.println("  lookupswitch ");
  
                                                for (int j = 0; j < 
targets.length; j++)
                                                        out.println("        " 
+ matchs[j] + " : "
                                                                        + 
targets[j].getPosition());
                                        }
  
                                        out.println("        default: " + 
s.getTarget()); // Applies
                                                                                
                                                          // for
                                                                                
                                                          // both
                                } else {
                                        BranchInstruction bi = 
(BranchInstruction) inst;
                                        ih = bi.getTarget();
                                        //str = get(ih);
                                        out.println("  " + 
Constants.OPCODE_NAMES[bi.getOpcode()]
                                                        + " " + ih);
                                }
                        } else
                                out.println("  " + 
inst.toString(cp.getConstantPool()));
                }
  
                out.print("\n");
  
                for (int i = 0; i < ehs.length; i++) {
                        CodeExceptionGen c = ehs[i];
                        ObjectType caught = c.getCatchType();
                        String class_name = (caught == null) ? // catch any 
exception, used
                                                                                
                   // when compiling finally
                                        "all" : 
caught.getClassName().replace('.', '/');
  
                        out.println("    catch " + class_name + " from "
                                        + c.getStartPC().getPosition() + " to "
                                        + c.getEndPC().getPosition() + " using "
                                        + c.getHandlerPC().getPosition());
                }
  
                printEndMethod(code);
        }
  }
  
  
  
  
  1.2       +3 -3      
cocoon-2.1/src/blocks/javaflow/java/org/apache/cocoon/components/flow/java/analyser/Subroutines.java
  
  Index: Subroutines.java
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.1/src/blocks/javaflow/java/org/apache/cocoon/components/flow/java/analyser/Subroutines.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Subroutines.java  3 Jun 2004 12:43:27 -0000       1.1
  +++ Subroutines.java  24 Jun 2004 16:48:53 -0000      1.2
  @@ -449,7 +449,7 @@
                
                // Now make sure no instruction of a Subroutine is protected by 
exception handling code
                // as is mandated by JustIces notion of subroutines.
  -             for (int i=0; i<handlers.length; i++){
  +             /*for (int i=0; i<handlers.length; i++){
                        InstructionHandle _protected = handlers[i].getStartPC();
                        while (_protected != 
handlers[i].getEndPC().getNext()){// Note the inclusive/inclusive notation of 
"generic API" exception handlers!
                                Enumeration subs = subroutines.elements();
  @@ -463,7 +463,7 @@
                                }
                                _protected = _protected.getNext();
                        }
  -             }
  +             }*/
                
                // Now make sure no subroutine is calling a subroutine
                // that uses the same local variable for the RET as themselves
  
  
  
  1.1                  
cocoon-2.1/src/blocks/javaflow/java/org/apache/cocoon/components/flow/javascript/JavaScriptHelper.java
  
  Index: JavaScriptHelper.java
  ===================================================================
  /*
   * 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.cocoon.components.flow.javascript;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  
  import org.apache.avalon.framework.CascadingRuntimeException;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.ResourceNotFoundException;
  import org.apache.cocoon.components.flow.Interpreter;
  import org.apache.cocoon.components.flow.java.AbstractContinuable;
  import org.apache.cocoon.environment.Redirector;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.environment.Session;
  import org.apache.commons.jxpath.JXPathIntrospector;
  import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl;
  import org.apache.excalibur.source.Source;
  import org.apache.excalibur.source.SourceResolver;
  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.NativeJavaClass;
  import org.mozilla.javascript.NativeJavaPackage;
  import org.mozilla.javascript.PropertyException;
  import org.mozilla.javascript.ScriptRuntime;
  import org.mozilla.javascript.Scriptable;
  import org.mozilla.javascript.ScriptableObject;
  import org.mozilla.javascript.Wrapper;
  import org.mozilla.javascript.tools.ToolErrorReporter;
  import org.mozilla.javascript.tools.shell.Global;
  
  /**
   * Interface with the JavaScript interpreter.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Ovidiu Predescu</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Marcus Crafter</a>
   * @since March 25, 2002
   * @version CVS $Id: JavaScriptHelper.java,v 1.1 2004/06/24 16:48:53 stephan 
Exp $
   */
  public class JavaScriptHelper extends AbstractContinuable
      implements ScriptHelper {
        
        /**
       * List of source locations that need to be resolved.
       */
      protected ArrayList needResolve = new ArrayList();
      
      /**
       * Whether reloading of scripts should be done. Specified through
       * the "reload-scripts" attribute in <code>flow.xmap</code>.
       */
      protected boolean reloadScripts;
  
      /**
       * Interval between two checks for modified script files. Specified
       * through the "check-time" XML attribute in <code>flow.xmap</code>.
       */
      protected long checkTime;
        
        /** A source resolver */
      protected SourceResolver sourceresolver;
      /**
       * Mapping of String objects (source uri's) to ScriptSourceEntry's
       */
      //protected Map compiledScripts = new HashMap();
  
      /**
       * LAST_EXEC_TIME
       * A long value is stored under this key in each top level JavaScript
       * thread scope object. When you enter a context any scripts whose
       * modification time is later than this value will be recompiled and 
reexecuted,
       * and this value will be updated to the current time.
       */
      private final static String LAST_EXEC_TIME = "__PRIVATE_LAST_EXEC_TIME__";
  
      /**
       * Key for storing a JavaScript global scope object in the Cocoon session
       */
      public static final String USER_GLOBAL_SCOPE = "FOM JavaScript GLOBAL 
SCOPE";
  
      // This is the only optimization level that supports continuations
      // in the Christoper Oliver's Rhino JavaScript implementation
      public static int OPTIMIZATION_LEVEL = -2;
  
      /**
       * When was the last time we checked for script modifications. Used
       * only if [EMAIL PROTECTED] #reloadScripts} is true.
       */
      protected long lastTimeCheck = 0;
  
      /**
       * Shared global scope for scripts and other immutable objects
       */
      private Global scope;
  
      /**
       * List of <code>String</code> objects that represent files to be
       * read in by the JavaScript interpreter.
       */
      private List topLevelScripts = new ArrayList();
  
      private JSErrorReporter errorReporter;
      private boolean enableDebugger = false;
      
      /**
       * 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
       * happens in two phases. In the first phase the file's location is
       * registered in the <code>needResolve</code> array.
       *
       * <p>The second is possible only when a Cocoon
       * <code>Environment</code> is passed to the Interpreter. This
       * allows the file location to be resolved using Cocoon's
       * <code>SourceFactory</code> class.
       *
       * <p>Once a file's location can be resolved, it is removed from the
       * <code>needResolve</code> array and placed in the
       * <code>scripts</code> hash table. The key in this hash table is
       * the file location string, and the value is a
       * DelayedRefreshSourceWrapper instance which keeps track of when
       * the file needs to re-read.
       *
       * @param source the location of the script
       *
       * @see org.apache.cocoon.environment.Environment
       * @see 
org.apache.cocoon.components.source.impl.DelayedRefreshSourceWrapper
       */
      public void register(String source)
      {
          synchronized(this) {
              needResolve.add(source);
          }
      }
  
      public void configure(Configuration config) throws ConfigurationException 
{
          
          reloadScripts = 
config.getChild("reload-scripts").getValueAsBoolean(false);
          checkTime = config.getChild("check-time").getValueAsLong(1000L);
  
          String loadOnStartup
              = config.getChild("load-on-startup", true).getValue(null);
          if (loadOnStartup != null) {
              register(loadOnStartup);
          }
  
          String debugger = config.getChild("debugger").getValue(null);
          if ("enabled".equalsIgnoreCase(debugger)) {
              enableDebugger = true;
          }
      }
  
      public void initialize() throws Exception {
          if (enableDebugger) {
              if (getLogger().isDebugEnabled()) {
                  getLogger().debug("Flow debugger enabled, creating");
              }
          }
          Context context = Context.enter();
          context.setOptimizationLevel(OPTIMIZATION_LEVEL);
          context.setCompileFunctionsWithDynamicScope(true);
          context.setGeneratingDebug(true);
          // add support for Rhino objects to JXPath
          JXPathIntrospector.registerDynamicClass(Scriptable.class,
                                                  
ScriptablePropertyHandler.class);
          JXPathContextReferenceImpl.addNodePointerFactory(new 
ScriptablePointerFactory());
  
          try {
              scope = new Global(context);
              // Access to Cocoon internal objects
              errorReporter = new JSErrorReporter(getLogger());
          } catch (Exception e) {
              Context.exit();
              e.printStackTrace();
              throw e;
          }
      }
  
      /**
       * Returns the JavaScript scope, a Scriptable object, from the user
       * session instance. Each sitemap can have a scope associated with it.
       *
       * @return a <code>Scriptable</code> value
       */
      private ThreadScope getSessionScope() throws Exception {
          Request request = getRequest();
          ThreadScope scope = null;
          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(getSitemapPath());
              }
          }
          if (scope == null) {
              scope = createThreadScope();
          }
          return scope;
      }
  
      void updateSession(Scriptable scope) throws Exception {
          ThreadScope thrScope = (ThreadScope)scope;
          if (thrScope.useSession) {
              setSessionScope(scope);
          }
      }
  
      /**
       * Associates a JavaScript scope, a Scriptable object, with the
       * directory path of the current sitemap, as resolved by the
       * source resolver.
       *
       * @param scope a <code>Scriptable</code> value
       */
      private Scriptable setSessionScope(Scriptable scope) throws Exception {
          Request request = getRequest();
  
          // 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);
              }
  
              // Attach the scope to the current context
              userScopes.put(getSitemapPath(), 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;
      }
  
      private String getSitemapPath() throws Exception {
          Source src = this.sourceresolver.resolveURI(".");
          try {
              return src.getURI();
          } finally {
              this.sourceresolver.release(src);
          }
      }
  
      public static class ThreadScope extends ScriptableObject {
          static final String[] builtinPackages = {"javax", "org", "com"};
  
          ClassLoader classLoader;
  
          /* true if this scope has assigned any global vars */
          boolean useSession = false;
  
          public ThreadScope() {
              final String[] names = { "importClass"};
  
              try {
                  this.defineFunctionProperties(names, ThreadScope.class,
                                                ScriptableObject.DONTENUM);
              } catch (PropertyException e) {
                  throw new Error();  // should never happen
              }
          }
  
          public String getClassName() {
              return "ThreadScope";
          }
  
          public void put(String name, Scriptable start, Object value) {
              useSession = true;
              super.put(name, start, value);
          }
  
          public void put(int index, Scriptable start, Object value) {
              useSession = true;
              super.put(index, start, value);
          }
  
          void reset() {
              useSession = false;
          }
  
          // Override importClass to allow reloading of classes
          public static void importClass(Context cx, Scriptable thisObj,
                                         Object[] args, Function funObj) {
              for (int i = 0; i < args.length; i++) {
                  Object cl = args[i];
                  if (!(cl instanceof NativeJavaClass)) {
                      throw Context.reportRuntimeError("Not a Java class: " +
                                                         Context.toString(cl));
                  }
                  String s = ((NativeJavaClass) cl).getClassObject().getName();
                  String n = s.substring(s.lastIndexOf('.')+1);
                  thisObj.put(n, thisObj, cl);
              }
          }
  
          public void setupPackages(ClassLoader cl) throws Exception {
              final String JAVA_PACKAGE = "JavaPackage";
              if (classLoader != cl) {
                  classLoader = cl;
                  Scriptable newPackages = new NativeJavaPackage("", cl);
                  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];
                      Scriptable pkg = new NativeJavaPackage(pkgName, cl);
                      pkg.setParentScope(this);
                      pkg.setPrototype(ScriptableObject.getClassPrototype(this, 
JAVA_PACKAGE));
                      super.put(pkgName, this, pkg);
                  }
              }
          }
  
          public ClassLoader getClassLoader() {
              return classLoader;
          }
      }
  
      private ThreadScope createThreadScope() throws Exception {
          Context context = Context.getCurrentContext();
  
          ThreadScope thrScope = new ThreadScope();
  
          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);
          // Put in the thread scope the Cocoon object, which gives access
          // to the interpreter object, and some Cocoon objects. See
          // FOM_Cocoon for more details.
          Object[] args = {};
          thrScope.defineProperty(LAST_EXEC_TIME,
                                  new Long(0),
                                  ScriptableObject.DONTENUM | 
ScriptableObject.PERMANENT);
  
          thrScope.reset();
          return thrScope;
      }
  
      /**
       * Returns a new Scriptable object to be used as the global scope
       * when running the JavaScript scripts in the context of a request.
       *
       * <p>If you want to maintain the state of global variables across
       * multiple invocations of <code>&lt;map:call
       * function="..."&gt;</code>, you need to instanciate the session
       * object which is a property of the cocoon object
       * <code>var session = cocoon.session</code>. This will place the
       * newly create Scriptable object in the user's session, where it
       * will be retrieved from at the next invocation of [EMAIL PROTECTED] 
#callFunction}.</p>
       *
       * @exception Exception if an error occurs
       */
      private void setupContext(Redirector redirector, Context context,
                                ThreadScope thrScope)
          throws Exception {
          // Try to retrieve the scope object from the session instance. If
          // no scope is found, we create a new one, but don't place it in
          // the session.
          //
          // When a user script "creates" a session using
          // cocoon.createSession() in JavaScript, the thrScope is placed in
          // the session object, where it's later retrieved from here. This
          // behaviour allows multiple JavaScript functions to share the
          // same global scope.
  
          long lastExecTime = ((Long)thrScope.get(LAST_EXEC_TIME,
                                                  thrScope)).longValue();
          boolean needsRefresh = false;
          if (reloadScripts) {
              long now = System.currentTimeMillis();
              if (now >= lastTimeCheck + checkTime) {
                  needsRefresh = true;
              }
              lastTimeCheck = now;
          }
          // We need to setup the FOM_Cocoon object according to the current
          // request. Everything else remains the same.
          //Thread.currentThread().setContextClassLoader(classLoader);
          //thrScope.setupPackages(classLoader);
  
          // Check if we need to compile and/or execute scripts
          /*synchronized (compiledScripts) {
              List execList = new ArrayList();
              // If we've never executed scripts in this scope or
              // if reload-scripts 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) {
                  topLevelScripts.addAll(needResolve);
                  if (lastExecTime != 0 && !needsRefresh) {
                      execList.addAll(needResolve);
                  } else {
                      execList.addAll(topLevelScripts);
                  }
                  needResolve.clear();
              }
              // 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) {
                      Source src = this.sourceresolver.resolveURI(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().getLastModified();
                  Script script = entry.getScript(context, this.scope, false, 
this);
                  if (lastExecTime == 0 || lastMod > lastExecTime) {
                      script.exec(context, thrScope);
                      thrScope.put(LAST_EXEC_TIME, thrScope,
                                   new Long(System.currentTimeMillis()));
                      thrScope.reset();
                  }
              }
          }*/
      }
  
      /**
       * Compile filename as JavaScript code
       *
       * @param cx Rhino context
       * @param fileName resource uri
       * @return compiled script
       */
      /*Script compileScript(Context cx, String fileName) throws Exception {
          Source src = this.sourceresolver.resolveURI(fileName);
          if (src != null) {
              synchronized (compiledScripts) {
                  ScriptSourceEntry entry =
                      (ScriptSourceEntry)compiledScripts.get(src.getURI());
                  Script compiledScript = null;
                  if (entry == null) {
                      compiledScripts.put(src.getURI(),
                              entry = new ScriptSourceEntry(src));
                  } else {
                      this.sourceresolver.release(src);
                  }
                  compiledScript = entry.getScript(cx, this.scope, false, this);
                  return compiledScript;
              }
          } else {
              throw new ResourceNotFoundException(fileName + ": not found");
          }
      }*/
  
      /*protected Script compileScript(Context cx, Scriptable scope, Source src)
              throws Exception {
          InputStream is = src.getInputStream();
          if (is != null) {
              try {
                  Reader reader = new BufferedReader(new InputStreamReader(is));
                  Script compiledScript = cx.compileReader(scope, reader,
                          src.getURI(), 1, null);
                  return compiledScript;
              } finally {
                  is.close();
              }
          } else {
              throw new ResourceNotFoundException(src.getURI() + ": not found");
          }
      }*/
  
      /**
       * Calls a JavaScript function, passing <code>params</code> as its
       * arguments. In addition to this, it makes available the parameters
       * through the <code>cocoon.parameters</code> JavaScript array
       * (indexed by the parameter names).
       *
       * @param funName a <code>String</code> value
       * @param params a <code>List</code> value
       * @param redirector
       * @exception Exception if an error occurs
       */
      public void callFunction(String funName, List params) 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 =
                  Thread.currentThread().getContextClassLoader();
              try {
                  try {
                      setupContext(getRedirector(), context, thrScope);
  
                      int size = (params != null ? params.size() : 0);
                      Object[] funArgs = new Object[size];
                      Scriptable parameters = context.newObject(thrScope);
                      for (int i = 0; i < size; i++) {
                          Interpreter.Argument arg = 
(Interpreter.Argument)params.get(i);
                          funArgs[i] = arg.value;
                          if (arg.name == null) {
                              arg.name = "";
                          }
                          parameters.put(arg.name, parameters, arg.value);
                      }
                      Object fun = ScriptableObject.getProperty(thrScope, 
funName);
                      if (fun == Scriptable.NOT_FOUND) {
                          throw new ResourceNotFoundException("Function 
\"javascript:" + funName + "()\" not found");
                      }
                      ScriptRuntime.call(context, fun, thrScope, funArgs, 
thrScope);
                  } catch (JavaScriptException ex) {
                      EvaluatorException ee = Context.reportRuntimeError(
                                                                         
ToolErrorReporter.getMessage("msg.uncaughtJSException",
                                                                                
                      ex.getMessage()));
                      Throwable unwrapped = unwrap(ex);
                      if (unwrapped instanceof ProcessingException) {
                          throw (ProcessingException)unwrapped;
                      }
                      throw new CascadingRuntimeException(ee.getMessage(),
                                                          unwrapped);
                  } 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 CascadingRuntimeException(ee.getMessage(), ee);
                  }
              } finally {
                  updateSession(thrScope);
                  Context.exit();
                  
Thread.currentThread().setContextClassLoader(savedClassLoader);
              }
          }
      }
  
      /*public void handleContinuation(String id, List params,
                                     Redirector redirector) throws Exception
      {
          WebContinuation wk = continuationsMgr.lookupWebContinuation(id);
  
          if (wk == null) {
              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 continuation object from it, and setup the
          // FOM_Cocoon object associated in the dynamic scope of the saved
          // continuation with the environment and context objects.
          Continuation k = (Continuation)wk.getContinuation();
          ThreadScope kScope = (ThreadScope)k.getParentScope();
          synchronized (kScope) {
              ClassLoader savedClassLoader =
                  Thread.currentThread().getContextClassLoader();
              FOM_Cocoon cocoon = null;
              try {
                  
Thread.currentThread().setContextClassLoader(kScope.getClassLoader());
                  cocoon = (FOM_Cocoon)kScope.get("cocoon", kScope);
                  cocoon.pushCallContext(this, redirector, getServiceManager(),
                                         getAvalonContext(),
                                         getLogger(), wk);
  
                  // Register the current scope for scripts indirectly called 
from this function
                  
FOM_JavaScriptFlowHelper.setFOM_FlowScope(cocoon.getObjectModel(), kScope);
  
                  Scriptable parameters = context.newObject(kScope);
                  int size = params != null ? params.size() : 0;
                  for (int i = 0; i < size; i++) {
                      Interpreter.Argument arg = 
(Interpreter.Argument)params.get(i);
                      parameters.put(arg.name, parameters, arg.value);
                  }
                  cocoon.setParameters(parameters);
                  FOM_WebContinuation fom_wk = new FOM_WebContinuation(wk);
                  fom_wk.setParentScope(kScope);
                  fom_wk.setPrototype(ScriptableObject.getClassPrototype(kScope,
                                                                         
fom_wk.getClassName()));
                  Object[] args = new Object[] {k, fom_wk};
                  try {
                      ScriptableObject.callMethod(cocoon,
                                                  "handleContinuation", args);
                  } catch (JavaScriptException ex) {
                      EvaluatorException ee = Context.reportRuntimeError(
                                                                         
ToolErrorReporter.getMessage("msg.uncaughtJSException",
                                                                                
                      ex.getMessage()));
                      Throwable unwrapped = unwrap(ex);
                      if (unwrapped instanceof ProcessingException) {
                          throw (ProcessingException)unwrapped;
                      }
                      throw new CascadingRuntimeException(ee.getMessage(),
                                                          unwrapped);
                  } 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 CascadingRuntimeException(ee.getMessage(), ee);
                  }
              } finally {
                  updateSession(kScope);
                  if (cocoon != null) {
                      cocoon.popCallContext();
                  }
                  Context.exit();
                  
Thread.currentThread().setContextClassLoader(savedClassLoader);
              }
          }
      }*/
  
      private Throwable unwrap(JavaScriptException e) {
          Object value = e.getValue();
          while (value instanceof Wrapper) {
              value = ((Wrapper)value).unwrap();
          }
          if (value instanceof Throwable) {
              return (Throwable)value;
          }
          return e;
      }
  
      /*private void setupView(Scriptable scope, FOM_Cocoon cocoon, 
FOM_WebContinuation kont) {
          Map objectModel = ContextHelper.getObjectModel(getAvalonContext());
  
          // Make the JS live-connect objects available to the view layer
          Request request = ObjectModelHelper.getRequest(objectModel);
          Scriptable session = null;
          if (request.getSession(false) != null) {
              session = cocoon.jsGet_session();
          }
          FOM_JavaScriptFlowHelper.setFOM_Session(objectModel, session);
  
          FOM_JavaScriptFlowHelper.setFOM_Context(objectModel,
                                                  cocoon.jsGet_context());
          if (kont != null) {
              FOM_JavaScriptFlowHelper.setFOM_WebContinuation(objectModel, 
kont);
          }
      }*/
      
      /*protected class ScriptSourceEntry {
          final private Source source;
          private Script script;
          private long compileTime;
  
          public ScriptSourceEntry(Source source) {
              this.source = source;
          }
  
          public ScriptSourceEntry(Source source, Script script, long t) {
              this.source = source;
              this.script = script;
              this.compileTime = t;
          }
  
          public Source getSource() {
              return source;
          }
  
          public Script getScript(Context context, Scriptable scope,
                                  boolean refresh, JavaScriptHelper interpreter)
              throws Exception {
              if (refresh) {
                  source.refresh();
              }
              if (script == null || compileTime < source.getLastModified()) {
                  script = interpreter.compileScript(context, scope, source);
                  compileTime = source.getLastModified();
              }
              return script;
          }
      }*/
  }
  
  
  
  1.1                  
cocoon-2.1/src/blocks/javaflow/java/org/apache/cocoon/components/flow/javascript/JavaScriptInterpreter.java
  
  Index: JavaScriptInterpreter.java
  ===================================================================
  /*
   * 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.cocoon.components.flow.javascript;
  
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  
  import org.apache.avalon.framework.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.cocoon.components.ContextHelper;
  import org.apache.cocoon.components.flow.AbstractInterpreter;
  import org.apache.cocoon.components.flow.FlowHelper;
  import org.apache.cocoon.components.flow.InvalidContinuationException;
  import org.apache.cocoon.components.flow.WebContinuation;
  import org.apache.cocoon.components.flow.java.Continuation;
  import org.apache.cocoon.components.flow.java.ContinuationClassLoader;
  import org.apache.cocoon.components.flow.java.ContinuationContext;
  import org.apache.cocoon.components.flow.java.VarMap;
  import org.apache.cocoon.components.flow.java.VarMapHandler;
  import org.apache.cocoon.environment.Redirector;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.environment.Session;
  import org.apache.commons.jxpath.JXPathIntrospector;
  
  /**
   * Implementation of the java flow interpreter.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Stephan Michels</a>
   * @version CVS $Id: JavaScriptInterpreter.java,v 1.1 2004/06/24 16:48:53 
stephan Exp $
   */
  public class JavaScriptInterpreter extends AbstractInterpreter implements 
Configurable {
  
      private boolean initialized = false;
  
      private int timeToLive = 600000;
  
      /**
       * Key for storing a global scope object in the Cocoon session
       */
      public static final String USER_GLOBAL_SCOPE = "JAVASCRIPT GLOBAL SCOPE";
  
      private ContinuationClassLoader continuationclassloader;
  
      private Configuration configuration;
  
      static {
          JXPathIntrospector.registerDynamicClass(VarMap.class, 
VarMapHandler.class);
      }
  
      public void configure(Configuration config) throws ConfigurationException 
{
          super.configure(config);
          
          continuationclassloader = new 
ContinuationClassLoader(Thread.currentThread().getContextClassLoader());
          
continuationclassloader.setDebug(config.getAttributeAsBoolean("debug", false));
  
          Configuration[] includes = config.getChildren("include");
          for (int i = 0; i < includes.length; i++)
              
continuationclassloader.addIncludeClass(includes[i].getAttribute("class"));
          
          this.configuration = config;
      }
  
      
      public ScriptHelper getScriptHelper() throws Exception {
          
          ScriptHelper flow = (ScriptHelper)continuationclassloader
                        
.loadClass("org.apache.cocoon.components.flow.javascript.JavaScriptHelper").newInstance();
  
          for (Iterator scripts = needResolve.iterator(); scripts.hasNext();) {
  
              String name = (String) scripts.next();
              flow.register(name);
          }
          
          flow.configure(configuration);
          flow.initialize();
          
          return flow;
      }
  
      /**
       * Calls a Java function, passing <code>params</code> as its
       * arguments. In addition to this, it makes available the parameters
       * through the <code>cocoon.parameters</code> Java array
       * (indexed by the parameter names).
       *
       * @param function a <code>String</code> value
       * @param params a <code>List</code> value
       * @param redirector
       * @exception Exception if an error occurs
       */
      public void callFunction(String function, List params, Redirector 
redirector) throws Exception {
  
          if (getLogger().isDebugEnabled())
              getLogger().debug("calling function \"" + function + "\"");
  
          Request request = ContextHelper.getRequest(this.avalonContext);
          Session session = request.getSession(true);
          ScriptHelper flow = (ScriptHelper) 
session.getAttribute(USER_GLOBAL_SCOPE);
  
          ContinuationContext context = new ContinuationContext();
          context.setObject(flow);
          context.setAvalonContext(avalonContext);
          context.setLogger(getLogger());
          context.setServiceManager(manager);
          context.setRedirector(redirector);
          Parameters parameters = new Parameters();
          for(Iterator i=params.iterator(); i.hasNext();) {
                Argument argument = (Argument)i.next();
                parameters.setParameter(argument.name, argument.value);
          }
          context.setParameters(parameters);
  
          Continuation continuation = new Continuation(context);
  
          WebContinuation wk = 
continuationsMgr.createWebContinuation(continuation, null, timeToLive, null);
          
FlowHelper.setWebContinuation(ContextHelper.getObjectModel(this.avalonContext), 
wk);
  
          continuation.registerThread();
          try {
              if (flow == null) {
                
                  if (getLogger().isDebugEnabled())
                      getLogger().debug("create new instance of the script 
helper");
                  
                  flow = getScriptHelper();
                  context.setObject(flow);
              }
  
              flow.callFunction(function, params);
  
          } finally {
              // remove last object reference, which is not needed to
              // reconstruct the invocation path
              if (continuation.isCapturing())
                  continuation.getStack().popReference();
              continuation.deregisterThread();
          }
          session.setAttribute(USER_GLOBAL_SCOPE, flow);
      }
  
      public void handleContinuation(String id, List params, Redirector 
redirector) throws Exception {
  
          WebContinuation parentwk = continuationsMgr.lookupWebContinuation(id);
  
          if (parentwk == null) {
          /*
           * Throw an InvalidContinuationException to be handled inside the
           * <map:handle-errors> sitemap element.
           */
          throw new InvalidContinuationException("The continuation ID " + id + 
" is invalid."); }
  
          Continuation parentContinuation = (Continuation) 
parentwk.getContinuation();
          ContinuationContext parentContext = (ContinuationContext) 
parentContinuation.getContext();
          ContinuationContext context = new ContinuationContext();
          context.setObject(parentContext.getObject());
          context.setAvalonContext(avalonContext);
          context.setLogger(getLogger());
          context.setServiceManager(manager);
          context.setRedirector(redirector);
          Parameters parameters = new Parameters();
          for(Iterator i=params.iterator(); i.hasNext();) {
                Argument argument = (Argument)i.next();
                parameters.setParameter(argument.name, argument.value);
          }
          context.setParameters(parameters);
          
          Continuation continuation = new Continuation(parentContinuation, 
context);
  
          Request request = ContextHelper.getRequest(this.avalonContext);
          Session session = request.getSession(true);
          HashMap userScopes = (HashMap) 
session.getAttribute(USER_GLOBAL_SCOPE);
  
          ScriptHelper flow = (ScriptHelper) context.getObject();
  
          WebContinuation wk = 
continuationsMgr.createWebContinuation(continuation, parentwk, timeToLive, 
null);
          
FlowHelper.setWebContinuation(ContextHelper.getObjectModel(this.avalonContext), 
wk);
  
          continuation.registerThread();
          try {
  
              flow.callFunction(null, null);
  
          } finally {
              // remove last object reference, which is not needed to 
reconstruct
              // the invocation path
              if (continuation.isCapturing())
                  continuation.getStack().popReference();
              continuation.deregisterThread();
          }
  
          session.setAttribute(USER_GLOBAL_SCOPE, flow);
      }
  }
  
  
  1.1                  
cocoon-2.1/src/blocks/javaflow/java/org/apache/cocoon/components/flow/javascript/ScriptHelper.java
  
  Index: ScriptHelper.java
  ===================================================================
  /*
   * Created on 24.06.2004
   *
   * TODO To change the template for this generated file go to
   * Window - Preferences - Java - Code Generation - Code and Comments
   */
  package org.apache.cocoon.components.flow.javascript;
  
  import java.util.List;
  
  import org.apache.avalon.framework.activity.Initializable;
  import org.apache.avalon.framework.configuration.Configurable;
  
  /**
   * @author stephan
   *
   * TODO To change the template for this generated type comment go to
   * Window - Preferences - Java - Code Generation - Code and Comments
   */
  public interface ScriptHelper extends Configurable, Initializable {
        
        public void register(String source);
  
        public void callFunction(String funName, List params) throws Exception;
  }
  
  
  
  1.3       +6 -1      
cocoon-2.1/src/blocks/javaflow/test/org/apache/cocoon/components/flow/java/test/JavaFlowTestCase.java
  
  Index: JavaFlowTestCase.java
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.1/src/blocks/javaflow/test/org/apache/cocoon/components/flow/java/test/JavaFlowTestCase.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- JavaFlowTestCase.java     23 Jun 2004 09:16:32 -0000      1.2
  +++ JavaFlowTestCase.java     24 Jun 2004 16:48:53 -0000      1.3
  @@ -160,4 +160,9 @@
           
           String id = callFunction("java", source, "parameterTest", 
parameters);
       }
  +    
  +    public void testClass() throws Exception {
  +        String source = 
"org.apache.cocoon.components.flow.java.test.SimpleFlow";
  +        String id = callFunction("java", source, "forClassTest", new 
HashMap());
  +    }
   }
  
  
  
  1.2       +1 -1      
cocoon-2.1/src/blocks/javaflow/test/org/apache/cocoon/components/flow/java/test/JavaFlowTestCase.xtest
  
  Index: JavaFlowTestCase.xtest
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.1/src/blocks/javaflow/test/org/apache/cocoon/components/flow/java/test/JavaFlowTestCase.xtest,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- JavaFlowTestCase.xtest    14 Jun 2004 14:53:56 -0000      1.1
  +++ JavaFlowTestCase.xtest    24 Jun 2004 16:48:53 -0000      1.2
  @@ -78,7 +78,7 @@
     <source-resolver 
class="org.apache.excalibur.source.impl.SourceResolverImpl"/>
   
     <flow-interpreters default="java">
  -    <component-instance 
class="org.apache.cocoon.components.flow.java.JavaInterpreter" name="java"/>
  +    <component-instance 
class="org.apache.cocoon.components.flow.java.JavaInterpreter" name="java" 
debug="false"/>
     </flow-interpreters>
   
     <continuations-manager time-to-live="3600000">
  
  
  
  1.7       +8 -0      
cocoon-2.1/src/blocks/javaflow/test/org/apache/cocoon/components/flow/java/test/SimpleFlow.java
  
  Index: SimpleFlow.java
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.1/src/blocks/javaflow/test/org/apache/cocoon/components/flow/java/test/SimpleFlow.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- SimpleFlow.java   23 Jun 2004 09:16:32 -0000      1.6
  +++ SimpleFlow.java   24 Jun 2004 16:48:53 -0000      1.7
  @@ -20,7 +20,10 @@
   import junit.framework.Assert;
   
   import org.apache.cocoon.components.flow.java.*;
  +import 
org.apache.cocoon.components.flow.javascript.ScriptablePropertyHandler;
   import org.apache.cocoon.forms.FormContext;
  +import org.apache.commons.jxpath.JXPathIntrospector;
  +import org.mozilla.javascript.Scriptable;
   /*import org.apache.lucene.analysis.standard.StandardAnalyzer;
   import org.apache.lucene.queryParser.QueryParser;
   import org.apache.lucene.search.*;*/
  @@ -130,6 +133,11 @@
        Assert.assertEquals("abc", getParameters().getParameter("p1")); 
        Assert.assertEquals("def", getParameters().getParameter("p2"));
        Assert.assertEquals(2.3f, getParameters().getParameterAsFloat("p3"), 
0.1f);
  +    }
  +    
  +    public void doClassTest() {
  +     JXPathIntrospector.registerDynamicClass(Scriptable.class,
  +         ScriptablePropertyHandler.class);
       }
   }
   
  
  
  
  1.3       +5 -3      
cocoon-2.1/src/blocks/javaflow/test/org/apache/cocoon/components/flow/javascript/JavaScriptFlowTestCase.java
  
  Index: JavaScriptFlowTestCase.java
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.1/src/blocks/javaflow/test/org/apache/cocoon/components/flow/javascript/JavaScriptFlowTestCase.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- JavaScriptFlowTestCase.java       14 Jun 2004 14:53:57 -0000      1.2
  +++ JavaScriptFlowTestCase.java       24 Jun 2004 16:48:53 -0000      1.3
  @@ -16,6 +16,8 @@
   
   package org.apache.cocoon.components.flow.javascript;
   
  +import java.util.HashMap;
  +
   import org.apache.cocoon.SitemapComponentTestCase;
   
   /**
  @@ -31,7 +33,7 @@
       }
       
       public void testCalculator() throws Exception {
  -        /*String source = 
"resource://org/apache/cocoon/components/flow/javascript/calc.js";
  -        callFunction("java", source, "calculator", new ArrayList());*/
  +        String source = 
"resource://org/apache/cocoon/components/flow/javascript/calc.js";
  +        callFunction("javascript", source, "calculator", new HashMap());
       }
   }
  
  
  
  1.2       +3 -2      
cocoon-2.1/src/blocks/javaflow/test/org/apache/cocoon/components/flow/javascript/JavaScriptFlowTestCase.xtest
  
  Index: JavaScriptFlowTestCase.xtest
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.1/src/blocks/javaflow/test/org/apache/cocoon/components/flow/javascript/JavaScriptFlowTestCase.xtest,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- JavaScriptFlowTestCase.xtest      4 Jun 2004 14:02:38 -0000       1.1
  +++ JavaScriptFlowTestCase.xtest      24 Jun 2004 16:48:53 -0000      1.2
  @@ -77,10 +77,11 @@
   
     <source-resolver 
class="org.apache.excalibur.source.impl.SourceResolverImpl"/>
   
  -  <flow-interpreters default="java">
  +  <flow-interpreters default="javascript">
       <component-instance 
class="org.apache.cocoon.components.flow.java.JavaInterpreter" name="java"/>
  +    <component-instance 
class="org.apache.cocoon.components.flow.javascript.JavaScriptInterpreter" 
name="javascript" debug="false"/>
     </flow-interpreters>
  -
  +  
     <continuations-manager time-to-live="3600000">
       <expirations-check type="periodic">
         <offset>180000</offset>
  
  
  

Reply via email to