ovidiu      2002/08/16 18:20:58

  Modified:    src/java/org/apache/cocoon/components/flow/javascript
                        JavaScriptInterpreter.java
  Log:
  Compile all the script files as a single large script using the
  Context.compileReader() method. This allows sharing the JavaScript
  bytecodes of the code between Scopes, at the same time separating the
  variables space between them (e.g. each user has its own global
  variables space).
  
  Revision  Changes    Path
  1.5       +109 -22   
xml-cocoon2/src/java/org/apache/cocoon/components/flow/javascript/JavaScriptInterpreter.java
  
  Index: JavaScriptInterpreter.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/flow/javascript/JavaScriptInterpreter.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- JavaScriptInterpreter.java        31 Jul 2002 13:13:22 -0000      1.4
  +++ JavaScriptInterpreter.java        17 Aug 2002 01:20:58 -0000      1.5
  @@ -42,32 +42,35 @@
    (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
  - This software  consists of voluntary contributions made  by many individuals
  - on  behalf of the Apache Software  Foundation and was  originally created by
  - Stefano Mazzocchi  <[EMAIL PROTECTED]>. For more  information on the Apache
  - Software Foundation, please see <http://www.apache.org/>.
  -
   */
   package org.apache.cocoon.components.flow.javascript;
   
  +
   import java.io.BufferedReader;
   import java.io.InputStream;
   import java.io.InputStreamReader;
   import java.io.Reader;
  +import java.io.SequenceInputStream;
  +import java.util.ArrayList;
  +import java.util.Enumeration;
   import java.util.List;
  +import org.apache.avalon.excalibur.collections.ArrayEnumeration;
   import org.apache.avalon.framework.activity.Initializable;
   import org.apache.avalon.framework.configuration.Configurable;
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
  -import org.apache.cocoon.components.flow.Interpreter;
   import org.apache.cocoon.components.flow.AbstractInterpreter;
  +import org.apache.cocoon.components.flow.Interpreter;
   import org.apache.cocoon.components.flow.WebContinuation;
   import org.apache.cocoon.environment.Environment;
  -import org.apache.excalibur.source.Source;
  +import org.apache.cocoon.environment.ModifiableSource;
  +import org.apache.cocoon.environment.Source;
   import org.mozilla.javascript.Context;
  +import org.mozilla.javascript.ErrorReporter;
   import org.mozilla.javascript.Function;
   import org.mozilla.javascript.NativeArray;
   import org.mozilla.javascript.PropertyException;
  +import org.mozilla.javascript.Script;
   import org.mozilla.javascript.ScriptRuntime;
   import org.mozilla.javascript.Scriptable;
   import org.mozilla.javascript.ScriptableObject;
  @@ -85,7 +88,20 @@
     // in the Christoper Oliver's Rhino JavaScript implementation
     static int OPTIMIZATION_LEVEL = -2;
   
  +  /**
  +   * List of <code>Source</code> objects that represent files to be
  +   * read in by the JavaScript interpreter.
  +   */
  +  protected List scripts = new ArrayList();
  +
  +  /**
  +   * When was the last time we checked for script modifications. Used
  +   * only if {@link #reloadScripts} is true.
  +   */
  +  protected long lastTimeCheck = 0;
     JSGlobal scope;
  +  Script compiledScript;
  +  JSErrorReporter errorReporter;
   
     public void configure(Configuration config)
     {
  @@ -148,6 +164,7 @@
       Context context = Context.enter();
       context.setOptimizationLevel(OPTIMIZATION_LEVEL);
       context.setCompileFunctionsWithDynamicScope(true);
  +    context.setErrorReporter(errorReporter);
       Scriptable thrScope = context.newObject(scope);
   
       thrScope.setPrototype(scope);
  @@ -181,21 +198,20 @@
       Context.getCurrentContext().exit();
     }
   
  -  public Source readScript(Environment environment, String sourceName)
  +  public void readScripts(Environment environment, ListInputStream is)
       throws Exception
     {
       Scriptable thrScope = null;
  -    Source source = null;
   
  -    System.out.println("Reading file " + sourceName);
  +    System.out.println("Reading scripts");
   
       try {
         thrScope = enterContext(environment);
  -      source = environment.resolveURI(sourceName);
  -      InputStream inputStream = source.getInputStream();
  -      Reader reader = new BufferedReader(new InputStreamReader(inputStream));
  +      Reader reader = new BufferedReader(new InputStreamReader(is));
         Context ctx = Context.getCurrentContext();
  -      ctx.evaluateReader(scope, reader, sourceName, 1, null);
  +
  +      compiledScript = ctx.compileReader(thrScope, reader,
  +                                         "(combined)", 1, null);
       }
       catch (Exception ex) {
         ex.printStackTrace();
  @@ -204,7 +220,74 @@
       finally {
         exitContext(thrScope);
       }
  -    return source;
  +  }
  +
  +  /**
  +   * Reloads any modified script files.
  +   *
  +   * <p>It checks to see if any of the files already read in (those
  +   * present in the <code>scripts</code> hash map) have been
  +   * modified.
  +   *
  +   * <p>It also checks to see if any script files have been registered
  +   * with the interpreter since the last call to
  +   * <code>checkForModifiedScripts</code>. These files are stored in
  +   * the temporary array <code>needResolve</code>. If any such files
  +   * are found, they are read in.
  +   *
  +   * @param environment an <code>Environment</code> value
  +   */
  +  public void checkForModifiedScripts(Environment environment)
  +    throws Exception
  +  {
  +    boolean needsRefresh = false;
  +
  +    if (reloadScripts
  +        && System.currentTimeMillis() >= lastTimeCheck + checkTime) {
  +      // FIXME: should we worry about synchronization?
  +      for (int i = 0, size = scripts.size(); i < size; i++) {
  +        Source src = (Source)scripts.get(i);
  +        if (src instanceof ModifiableSource)
  +          ((ModifiableSource)src).refresh();
  +        getLogger().debug("Checking " + src.getSystemId()
  +                           + ", source " + src
  +                           + ", last modified " + src.getLastModified()
  +                           + ", last time check " + lastTimeCheck);
  +        if (src.getLastModified() > lastTimeCheck) {
  +          needsRefresh = true;
  +          break;
  +        }
  +      }
  +    }
  +
  +    // FIXME: remove the need for synchronization
  +    synchronized (this) {
  +      int size = needResolve.size();
  +
  +      // If there's no need to re-read any file, and no files
  +      // have been requested to be read since the last time,
  +      // don't do anything.
  +      if (!needsRefresh && size == 0) {
  +        lastTimeCheck = System.currentTimeMillis();
  +        return;
  +      }
  +
  +      for (int i = 0; i < size; i++) {
  +        String source = (String)needResolve.get(i);
  +        Source src = environment.resolve(source);
  +        scripts.add(src);
  +      }
  +      needResolve.clear();
  +
  +      ListInputStream is = new ListInputStream(scripts);
  +      errorReporter = new JSErrorReporter(is.getSourceInfo());
  +      readScripts(environment, is);
  +    }
  +
  +    // Update the time of the last check. If an exception occurs, this
  +    // is not executed, so the next request will force a reparse of
  +    // the script files because of an old time stamp.
  +    lastTimeCheck = System.currentTimeMillis();
     }
   
     /**
  @@ -228,21 +311,22 @@
   
       try {
         thrScope = enterContext(environment);
  +      Context cx = Context.getCurrentContext();
  +
  +      compiledScript.exec(cx, thrScope);
         JSCocoon cocoon = (JSCocoon)thrScope.get("cocoon", thrScope);
   
  -      Object callFunction = scope.get("callFunction", thrScope);
  +      Object callFunction = thrScope.get("callFunction", thrScope);
         if (callFunction == Scriptable.NOT_FOUND)
  -          throw new RuntimeException("Cannot find 'callFunction' "
  -                                     + "(system.js not loaded?)");
  +        throw new RuntimeException("Cannot find 'callFunction' "
  +                                   + "(system.js not loaded?)");
   
  -      Object fun = scope.get(funName, thrScope);
  +      Object fun = thrScope.get(funName, thrScope);
         if (fun == Scriptable.NOT_FOUND)
           throw new RuntimeException("'" + funName + "' is undefined!");
         if (!(fun instanceof Function))
           throw new RuntimeException("'" + funName + "' is not a function!");
   
  -      Context cx = Context.getCurrentContext();
  -
         int size = (params != null ? params.size() : 0);
         Object[] funArgs = new Object[size];
         NativeArray funArgsArray = new NativeArray(funArgs);
  @@ -260,6 +344,9 @@
         Object callFunArgs[] = { fun, funArgsArray };
         ((Function) callFunction).call(cx, thrScope, thrScope, callFunArgs);
       }
  +    catch (Exception ex) {
  +      ex.printStackTrace();
  +    }
       finally {
         exitContext(thrScope);
       }
  @@ -288,7 +375,7 @@
   
       // We can now resume the processing from the state saved by the
       // continuation object. Setup the JavaScript Context object.
  -    Object handleContFunction = scope.get("handleContinuation", kScope);
  +    Object handleContFunction = kScope.get("handleContinuation", kScope);
       if (handleContFunction == Scriptable.NOT_FOUND)
         throw new RuntimeException("Cannot find 'handleContinuation' "
                                    + "(system.js not loaded?)");
  
  
  

----------------------------------------------------------------------
In case of troubles, e-mail:     [EMAIL PROTECTED]
To unsubscribe, e-mail:          [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to