coliver     2003/03/15 01:56:04

  Modified:    src/java/org/apache/cocoon/components/flow/javascript
                        JSCocoon.java JSErrorReporter.java
                        JavaScriptInterpreter.java
                        ScriptableConnection.java
  Removed:     src/java/org/apache/cocoon/components/flow/javascript
                        ListInputStream.java SourceInfo.java
  Log:
  fixed error handling and the cocoon.load() function
  
  Revision  Changes    Path
  1.2       +336 -325  
cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/JSCocoon.java
  
  Index: JSCocoon.java
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/JSCocoon.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- JSCocoon.java     9 Mar 2003 00:08:50 -0000       1.1
  +++ JSCocoon.java     15 Mar 2003 09:56:04 -0000      1.2
  @@ -55,6 +55,9 @@
   import org.mozilla.javascript.Scriptable;
   import org.mozilla.javascript.ScriptRuntime;
   import org.mozilla.javascript.NativeArray;
  +import org.mozilla.javascript.Script;
  +import org.mozilla.javascript.JavaScriptException;
  +
   import org.apache.cocoon.sitemap.SitemapRedirector;
   import org.apache.cocoon.environment.SourceResolver;
   import org.apache.cocoon.environment.Session;
  @@ -88,362 +91,370 @@
    */
   public class JSCocoon extends ScriptableObject
   {
  -  protected static String OBJECT_SOURCE_RESOLVER = "source-resolver";
  -  protected JavaScriptInterpreter interpreter;
  -  protected Scriptable scope;
  -  protected NativeArray parameters;
  -  protected Environment environment;
  -  protected ComponentManager manager;
  -
  -  public JSCocoon() {}
  -
  -  public String getClassName()
  -  {
  -    return "Cocoon";
  -  }
  -
  -  public void setScope(Scriptable scope)
  -  {
  -    this.scope = scope;
  -  }
  -
  -  public Scriptable getScope()
  -  {
  -    return scope;
  -  }
  -
  -  public void setParameters(NativeArray parameters)
  -  {
  -    this.parameters = parameters;
  -  }
  -
  -  public void setInterpreter(JavaScriptInterpreter interpreter)
  -  {
  -    this.interpreter = interpreter;
  -  }
  -
  -  public void setContext(ComponentManager manager, Environment environment)
  -  {
  -    this.manager = manager;
  -    this.environment = environment;
  -  }
  -
  -  public void invalidateContext()
  -  {
  -    manager = null;
  -    environment = null;
  -  }
  -
  -  public NativeArray jsGet_parameters()
  -  {
  -    return parameters;
  -  }
  -
  -  public JavaScriptInterpreter jsGet_interpreter()
  -  {
  -    return interpreter;
  -  }
  -
  -  public Environment jsGet_environment()
  -  {
  -    return environment;
  -  }
  -
  -  public Request jsGet_request()
  -  {
  -      if (environment == null) {
  -        // context has been invalidated
  -        return null;
  -      }
  -      Map objectModel = environment.getObjectModel();
  -      return ObjectModelHelper.getRequest(objectModel);
  -  }
  -
  -  public Response jsGet_response()
  -  {
  -      if (environment == null) {
  -        // context has been invalidated
  -        return null;
  -      }
  -    Map objectModel = environment.getObjectModel();
  -    return ObjectModelHelper.getResponse(objectModel);
  -  }
  -
  -  public Session jsGet_session()
  -  {
  -      if (environment == null) {
  -        // context has been invalidated
  -        return null;
  -      }
  -    return jsGet_request().getSession();
  -  }
  -
  -  public Context jsGet_context()
  -  {
  -      if (environment == null) {
  -        // context has been invalidated
  -        return null;
  -      }
  -    Map objectModel = environment.getObjectModel();
  -    return ObjectModelHelper.getContext(objectModel);
  -  }
  -
  -  public ComponentManager jsGet_componentManager()
  -  {
  -    return manager;
  -  }
  -
  -
  -
  -  /**
  -   * Load the file specified as argument. Registers the file with the
  -   * interpreter and then forces its loading by calling [EMAIL PROTECTED]
  -   * JavaScriptInterpreter#checkForModifiedScripts}.
  -   *
  -   * @param filename a <code>String</code> value
  -   * @return an <code>Object</code> value
  -   * @exception Exception if an error occurs
  -   */
  -  public Object jsFunction_load(String filename)
  -    throws Exception
  -  {
  -    try {
  -      interpreter.register(filename);
  -      interpreter.checkForModifiedScripts(environment);
  -    }
  -    catch (Exception ex) {
  -      ex.printStackTrace();
  -      throw ex;
  -    }
  -    return null;
  -  }
  -
  -  public String jsFunction_toString()
  -  {
  -    return "[object " + toString() + "]";
  -  }
  -
  -  public void jsFunction_forwardTo(String uri, Object bizData, Object cont)
  -    throws Exception
  -  {
  -    bizData = jsobjectToObject(bizData);
  -    
  -    WebContinuation kont = null;
  -
  -    if (cont != null)
  -      kont = ((JSWebContinuation)cont).getWebContinuation();
  -
  -    if (bizData != null) System.err.println("FWD:" + bizData.getClass().getName());
  -
  -    interpreter.forwardTo(uri, bizData, kont, environment);
  -  }
  -
  -  /**
  -   * Call the Cocoon sitemap for the given URI, sending the output of the
  -   * eventually matched pipeline to the specified outputstream.
  -   *
  -   * @param uri The URI for which the request should be generated.
  -   * @param biz Extra data associated with the subrequest.
  -   * @param out An OutputStream where the output should be written to.
  -   * @return Whatever the Cocoon processor returns (????).
  -   * @exception Exception If an error occurs.
  -   */
  -  public boolean jsFunction_process(String uri, Object biz, Object out)
  -    throws Exception
  -  {
  -    out = jsobjectToObject(out);
  -    biz = jsobjectToObject(biz);
  -    if (biz != null) System.err.println("PRC:"+biz.getClass().getName());
  -    return interpreter.process(uri, biz, (OutputStream)out, environment);
  -  }
  -
  -  /**
  -     Set the Scope object in the session object of the current
  -     user. This effectively means that at the next invocation from the
  -     sitemap of a JavaScript function (using the &lt;map:call
  -     function="..."&gt;), will obtain the same scope as the current
  -     one.
  -  */
  -  public void jsFunction_createSession()
  -  {
  -    interpreter.setSessionScope(environment, scope);
  -  }
  -
  -  /**
  -     Remove the Scope object from the session object of the current
  -     user.
  -  */
  -  public void jsFunction_removeSession()
  -  {
  -    interpreter.removeSessionScope(environment);
  -  }
  -
  -  public void jsFunction_diplayAllContinuations()
  -    throws ComponentException
  -  {
  -    ContinuationsManager continuationsMgr
  -      = (ContinuationsManager)manager.lookup(ContinuationsManager.ROLE);
  -
  -    try {
  -      if (continuationsMgr instanceof ContinuationsManagerImpl)
  -        ((ContinuationsManagerImpl)continuationsMgr).displayAllContinuations();
  -    }
  -    finally {
  -      manager.release((Component)continuationsMgr);
  -    }
  -  }
  -
  -  // All right, this breaks the encapsulation, but I couldn't find any
  -  // better way to obtain the ComponentManager for a
  -  // JSWebContinuation.
  -  ComponentManager getComponentManager()
  -  {
  -    return manager;
  -  }
  -
  -
  -  public static Map jsobjectToMap(Scriptable jsobject)
  -  {
  -    HashMap hash = new HashMap();
  -    Object[] ids = jsobject.getIds();
  -    for (int i = 0; i < ids.length; i++) {
  -      String key = ScriptRuntime.toString(ids[i]);
  -      Object value = jsobject.get(key, jsobject);
  -      if (value == Undefined.instance)
  -        value = null;
  -      else
  -        value = jsobjectToObject(value);
  -      hash.put(key, value);
  -    }
  -    return hash;
  -  }
  -
  -  public static Object jsobjectToObject(Object obj) 
  -  {
  -     // unwrap Scriptable wrappers of real Java objects
  -    if (obj instanceof Wrapper) {
  -      obj = ((Wrapper) obj).unwrap();
  -    } else if (obj == Undefined.instance) {
  -      obj = null;
  +    protected static String OBJECT_SOURCE_RESOLVER = "source-resolver";
  +    protected JavaScriptInterpreter interpreter;
  +    protected Scriptable scope;
  +    protected NativeArray parameters;
  +    protected Environment environment;
  +    protected ComponentManager manager;
  +
  +    public JSCocoon() {}
  +
  +    public String getClassName()
  +    {
  +        return "Cocoon";
  +    }
  +
  +    public void setScope(Scriptable scope)
  +    {
  +        this.scope = scope;
  +    }
  +
  +    public Scriptable getScope()
  +    {
  +        return scope;
  +    }
  +
  +    public void setParameters(NativeArray parameters)
  +    {
  +        this.parameters = parameters;
  +    }
  +
  +    public void setInterpreter(JavaScriptInterpreter interpreter)
  +    {
  +        this.interpreter = interpreter;
  +    }
  +
  +    public void setContext(ComponentManager manager, Environment environment)
  +    {
  +        this.manager = manager;
  +        this.environment = environment;
  +    }
  +
  +    public void invalidateContext()
  +    {
  +        manager = null;
  +        environment = null;
  +    }
  +
  +    public NativeArray jsGet_parameters()
  +    {
  +        return parameters;
  +    }
  +
  +    public JavaScriptInterpreter jsGet_interpreter()
  +    {
  +        return interpreter;
  +    }
  +
  +    public Environment jsGet_environment()
  +    {
  +        return environment;
  +    }
  +
  +    public Request jsGet_request()
  +    {
  +        if (environment == null) {
  +            // context has been invalidated
  +            return null;
  +        }
  +        Map objectModel = environment.getObjectModel();
  +        return ObjectModelHelper.getRequest(objectModel);
  +    }
  +
  +    public Response jsGet_response()
  +    {
  +        if (environment == null) {
  +            // context has been invalidated
  +            return null;
  +        }
  +        Map objectModel = environment.getObjectModel();
  +        return ObjectModelHelper.getResponse(objectModel);
  +    }
  +
  +    public Session jsGet_session()
  +    {
  +        if (environment == null) {
  +            // context has been invalidated
  +            return null;
  +        }
  +        return jsGet_request().getSession();
  +    }
  +
  +    public Context jsGet_context()
  +    {
  +        if (environment == null) {
  +            // context has been invalidated
  +            return null;
  +        }
  +        Map objectModel = environment.getObjectModel();
  +        return ObjectModelHelper.getContext(objectModel);
  +    }
  +
  +    public ComponentManager jsGet_componentManager()
  +    {
  +        return manager;
  +    }
  +
  +
  +
  +    /**
  +     * Load the file specified as argument. Registers the file with the
  +     * interpreter and then forces its loading by calling [EMAIL PROTECTED]
  +     * JavaScriptInterpreter#checkForModifiedScripts}.
  +     *
  +     * @param filename a <code>String</code> value
  +     * @return an <code>Object</code> value
  +     * @exception Exception if an error occurs
  +     */
  +    public Object jsFunction_load(String filename) throws JavaScriptException
  +    {
  +        org.mozilla.javascript.Context cx = 
  +            org.mozilla.javascript.Context.getCurrentContext(); 
  +        try {
  +            Script script = interpreter.compileScript(cx, environment, filename);
  +            return script.exec(cx, ScriptableObject.getTopLevelScope(this));
  +        } catch (JavaScriptException e) {
  +            throw e;
  +        } catch (Exception e) {
  +            throw new JavaScriptException(e);
  +        }
  +    }
  +
  +    public String jsFunction_toString()
  +    {
  +        return "[object " + toString() + "]";
  +    }
  +
  +    public void jsFunction_forwardTo(String uri, Object bizData, Object cont)
  +        throws JavaScriptException 
  +    {
  +        try {
  +            bizData = jsobjectToObject(bizData);
  +            
  +            WebContinuation kont = null;
  +            
  +            if (cont != null)
  +                kont = ((JSWebContinuation)cont).getWebContinuation();
  +            
  +            interpreter.forwardTo(uri, bizData, kont, environment);
  +        } catch (JavaScriptException e) {
  +            throw e;
  +        } catch (Exception e) {
  +            throw new JavaScriptException(e);
  +        }
  +    }
  +
  +    /**
  +     * Call the Cocoon sitemap for the given URI, sending the output of the
  +     * eventually matched pipeline to the specified outputstream.
  +     *
  +     * @param uri The URI for which the request should be generated.
  +     * @param biz Extra data associated with the subrequest.
  +     * @param out An OutputStream where the output should be written to.
  +     * @return Whatever the Cocoon processor returns (????).
  +     */
  +    public boolean jsFunction_process(String uri, Object biz, Object out)
  +        throws JavaScriptException
  +    {
  +        try {
  +            out = jsobjectToObject(out);
  +            biz = jsobjectToObject(biz);
  +            return interpreter.process(uri, biz, (OutputStream)out, environment);
  +        } catch (JavaScriptException e) {
  +            throw e;
  +        } catch (Exception e) {
  +            throw new JavaScriptException(e);
  +        }
  +    }
  +
  +    /**
  +       Set the Scope object in the session object of the current
  +       user. This effectively means that at the next invocation from the
  +       sitemap of a JavaScript function (using the &lt;map:call
  +       function="..."&gt;), will obtain the same scope as the current
  +       one.
  +    */
  +    public void jsFunction_createSession()
  +    {
  +        interpreter.setSessionScope(environment, scope);
  +    }
  +
  +    /**
  +       Remove the Scope object from the session object of the current
  +       user.
  +    */
  +    public void jsFunction_removeSession()
  +    {
  +        interpreter.removeSessionScope(environment);
  +    }
  +
  +    public void jsFunction_diplayAllContinuations()
  +        throws ComponentException
  +    {
  +        ContinuationsManager continuationsMgr
  +            = (ContinuationsManager)manager.lookup(ContinuationsManager.ROLE);
  +
  +        try {
  +            if (continuationsMgr instanceof ContinuationsManagerImpl)
  +                
((ContinuationsManagerImpl)continuationsMgr).displayAllContinuations();
  +        }
  +        finally {
  +            manager.release((Component)continuationsMgr);
  +        }
  +    }
  +
  +    // All right, this breaks the encapsulation, but I couldn't find any
  +    // better way to obtain the ComponentManager for a
  +    // JSWebContinuation.
  +    ComponentManager getComponentManager()
  +    {
  +        return manager;
  +    }
  +
  +
  +    public static Map jsobjectToMap(Scriptable jsobject)
  +    {
  +        HashMap hash = new HashMap();
  +        Object[] ids = jsobject.getIds();
  +        for (int i = 0; i < ids.length; i++) {
  +            String key = ScriptRuntime.toString(ids[i]);
  +            Object value = jsobject.get(key, jsobject);
  +            if (value == Undefined.instance)
  +                value = null;
  +            else
  +                value = jsobjectToObject(value);
  +            hash.put(key, value);
  +        }
  +        return hash;
  +    }
  +
  +    public static Object jsobjectToObject(Object obj) 
  +    {
  +        // unwrap Scriptable wrappers of real Java objects
  +        if (obj instanceof Wrapper) {
  +            obj = ((Wrapper) obj).unwrap();
  +        } else if (obj == Undefined.instance) {
  +            obj = null;
  +        }
  +        return obj;
       }
  -    return obj;
  -  }
   
       public Scriptable jsFunction_callAction(String type,
                                               String source,
                                               Scriptable parameters)
           throws Exception
       {
  -      Redirector redirector = new SitemapRedirector(this.environment);
  -      SourceResolver resolver = (SourceResolver)this.environment.getObjectModel()
  -          .get(OBJECT_SOURCE_RESOLVER);
  -      ComponentManager sitemapManager = 
CocoonComponentManager.getSitemapComponentManager();
  -      ComponentSelector actionSelector
  -          = (ComponentSelector)sitemapManager.lookup(Action.ROLE + "Selector");
  -      Action action = (Action)actionSelector.select(type);
  -      Map result = null;
  -      try {
  -        result = action.act(redirector, 
  -                            resolver,
  -                            this.environment.getObjectModel(),
  -                            source, 
  -                            jsobjectToParameters(parameters));
  -      }
  -      finally {
  -        actionSelector.release(action);
  -      }
  -
  -      // what should be done with the redirector ??
  -      // ignore it or call sendPage with it?
  -      return (result!=null? new ScriptableMap(result) : null);
  +        Redirector redirector = new SitemapRedirector(this.environment);
  +        SourceResolver resolver = (SourceResolver)this.environment.getObjectModel()
  +            .get(OBJECT_SOURCE_RESOLVER);
  +        ComponentManager sitemapManager = 
CocoonComponentManager.getSitemapComponentManager();
  +        ComponentSelector actionSelector
  +            = (ComponentSelector)sitemapManager.lookup(Action.ROLE + "Selector");
  +        Action action = (Action)actionSelector.select(type);
  +        Map result = null;
  +        try {
  +            result = action.act(redirector, 
  +                                resolver,
  +                                this.environment.getObjectModel(),
  +                                source, 
  +                                jsobjectToParameters(parameters));
  +        }
  +        finally {
  +            actionSelector.release(action);
  +        }
  +
  +        // what should be done with the redirector ??
  +        // ignore it or call sendPage with it?
  +        return (result!=null? new ScriptableMap(result) : null);
       }
   
       public static Parameters jsobjectToParameters(Scriptable jsobject)
       {
  -      Parameters params = new Parameters();
  -      Object[] ids = jsobject.getIds();
  -      for (int i = 0; i < ids.length; i++) {
  -        String key = ScriptRuntime.toString(ids[i]);
  -        Object value = jsobject.get(key, jsobject);
  -        if (value == Undefined.instance)
  -          value = null;
  -        else
  -          value = ScriptRuntime.toString(value);
  -        params.setParameter(key, (String) value);
  -      }
  -      return params;
  +        Parameters params = new Parameters();
  +        Object[] ids = jsobject.getIds();
  +        for (int i = 0; i < ids.length; i++) {
  +            String key = ScriptRuntime.toString(ids[i]);
  +            Object value = jsobject.get(key, jsobject);
  +            if (value == Undefined.instance)
  +                value = null;
  +            else
  +                value = ScriptRuntime.toString(value);
  +            params.setParameter(key, (String) value);
  +        }
  +        return params;
       }
   
       public Object jsFunction_inputModuleGetAttribute(String type, String attribute)
           throws Exception
       {
  -      // since no new components can be declared on sitemap we could
  -      // very well use the 'other' one here. Anyway, since it's there...
  -      ComponentManager sitemapManager = 
CocoonComponentManager.getSitemapComponentManager();
  -      ComponentSelector inputSelector = (ComponentSelector)sitemapManager
  -          .lookup(InputModule.ROLE + "Selector");
  -      InputModule input = (InputModule) inputSelector.select(type);
  -      Object result = null;
  -      try {
  -        result = input.getAttribute(attribute, null,
  -                                    this.environment.getObjectModel());
  -      }
  -      finally {
  -        inputSelector.release(input);
  -      }
  -      return result;
  +        // since no new components can be declared on sitemap we could
  +        // very well use the 'other' one here. Anyway, since it's there...
  +        ComponentManager sitemapManager = 
CocoonComponentManager.getSitemapComponentManager();
  +        ComponentSelector inputSelector = (ComponentSelector)sitemapManager
  +            .lookup(InputModule.ROLE + "Selector");
  +        InputModule input = (InputModule) inputSelector.select(type);
  +        Object result = null;
  +        try {
  +            result = input.getAttribute(attribute, null,
  +                                        this.environment.getObjectModel());
  +        }
  +        finally {
  +            inputSelector.release(input);
  +        }
  +        return result;
       }
   
       public void jsFunction_outputModuleSetAttribute(String type, String attribute,
                                                       Object value)
           throws Exception
       {
  -      // since no new components can be declared on sitemap we could
  -      // very well use the 'other' one here. Anyway, since it's there...
  -      ComponentManager sitemapManager = 
CocoonComponentManager.getSitemapComponentManager();
  -      ComponentSelector outputSelector = (ComponentSelector)sitemapManager
  -          .lookup(OutputModule.ROLE + "Selector");
  -      OutputModule output = (OutputModule) outputSelector.select(type);
  -      try {
  -        output.setAttribute(null, this.environment.getObjectModel(), attribute,
  -                            jsobjectToObject(value));
  -      }
  -      finally {
  -        outputSelector.release(output);
  -      }
  +        // since no new components can be declared on sitemap we could
  +        // very well use the 'other' one here. Anyway, since it's there...
  +        ComponentManager sitemapManager = 
CocoonComponentManager.getSitemapComponentManager();
  +        ComponentSelector outputSelector = (ComponentSelector)sitemapManager
  +            .lookup(OutputModule.ROLE + "Selector");
  +        OutputModule output = (OutputModule) outputSelector.select(type);
  +        try {
  +            output.setAttribute(null, this.environment.getObjectModel(), attribute,
  +                                jsobjectToObject(value));
  +        }
  +        finally {
  +            outputSelector.release(output);
  +        }
       }
   
       public void jsFunction_outputModuleCommit(String type)
           throws Exception
       {
  -      // since no new components can be declared on sitemap we could
  -      // very well use the 'other' one here. Anyway, since it's there...
  -      ComponentManager sitemapManager = 
CocoonComponentManager.getSitemapComponentManager();
  -      ComponentSelector outputSelector = (ComponentSelector)sitemapManager
  -          .lookup(OutputModule.ROLE + "Selector");
  -      OutputModule output = (OutputModule) outputSelector.select(type);
  -      try {
  -        output.commit(null, this.environment.getObjectModel());
  -      }
  -      finally {
  -        outputSelector.release(output);
  -      }
  +        // since no new components can be declared on sitemap we could
  +        // very well use the 'other' one here. Anyway, since it's there...
  +        ComponentManager sitemapManager = 
CocoonComponentManager.getSitemapComponentManager();
  +        ComponentSelector outputSelector = (ComponentSelector)sitemapManager
  +            .lookup(OutputModule.ROLE + "Selector");
  +        OutputModule output = (OutputModule) outputSelector.select(type);
  +        try {
  +            output.commit(null, this.environment.getObjectModel());
  +        }
  +        finally {
  +            outputSelector.release(output);
  +        }
       }
   
       public void jsFunction_outputModuleRollback(String type)
           throws Exception
       {
  -      // since no new components can be declared on sitemap we could
  -      // very well use the 'other' one here. Anyway, since it's there...
  -      ComponentManager sitemapManager = 
CocoonComponentManager.getSitemapComponentManager();
  -      ComponentSelector outputSelector = (ComponentSelector)sitemapManager
  -          .lookup(OutputModule.ROLE + "Selector");
  -      OutputModule output = (OutputModule) outputSelector.select(type);
  -      try {
  -        output.rollback(null, this.environment.getObjectModel(), null);
  -      }
  -      finally {
  -        outputSelector.release(output);
  -      }
  +        // since no new components can be declared on sitemap we could
  +        // very well use the 'other' one here. Anyway, since it's there...
  +        ComponentManager sitemapManager = 
CocoonComponentManager.getSitemapComponentManager();
  +        ComponentSelector outputSelector = (ComponentSelector)sitemapManager
  +            .lookup(OutputModule.ROLE + "Selector");
  +        OutputModule output = (OutputModule) outputSelector.select(type);
  +        try {
  +            output.rollback(null, this.environment.getObjectModel(), null);
  +        }
  +        finally {
  +            outputSelector.release(output);
  +        }
       }
   }
  
  
  
  1.2       +37 -76    
cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/JSErrorReporter.java
  
  Index: JSErrorReporter.java
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/JSErrorReporter.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- JSErrorReporter.java      9 Mar 2003 00:08:50 -0000       1.1
  +++ JSErrorReporter.java      15 Mar 2003 09:56:04 -0000      1.2
  @@ -2,64 +2,53 @@
   
   import org.mozilla.javascript.ErrorReporter;
   import org.mozilla.javascript.EvaluatorException;
  -
  -import java.util.List;
  +import org.mozilla.javascript.tools.ToolErrorReporter;
  +import org.apache.avalon.framework.logger.Logger;
   
   /**
    * Implements a Rhino JavaScript [EMAIL PROTECTED]
  - * org.mozilla.javascript.ErrorReporter}. This is used to explicitly
  - * refer to the error in the original source files, rather than the
  - * combined file as presented for parsing by [EMAIL PROTECTED] ListInputStream}
  - * in [EMAIL PROTECTED] JavaScriptInterpreter#readScripts}.
  - *
  - * <p>When an error is reported, either during the parsing of the
  - * JavaScript files, or at runtime, an instance of this class is
  - * invoked. This class maintains a list of [EMAIL PROTECTED] SourceInfo} objects,
  - * which contain the original [EMAIL PROTECTED]
  - * org.apache.cocoon.environment.Source} object and the line numbers
  - * in it. When the error happens, the reporter matches the aggregated
  - * line number to the actual source of the error.
  - *
  - * @author <a href="mailto:[EMAIL PROTECTED]">Ovidiu Predescu</a>
  - * @since August 15, 2002
  + * org.mozilla.javascript.ErrorReporter}. 
  + * Like ToolErrorReporter but logs to supplied logger instead of stdout
    */
   public class JSErrorReporter implements ErrorReporter
   {
  -  /**
  -   * List of [EMAIL PROTECTED] SourceInfo} objects.
  -   */
  -  protected List sourcesInfo;
  +  private Logger logger;
   
  -  public JSErrorReporter(List sourcesInfo)
  +  public JSErrorReporter(Logger logger)
     {
  -    this.sourcesInfo = sourcesInfo;
  +      this.logger = logger;
     }
   
     public void error(String message,
                       String sourceName, int line,
                       String lineSrc, int column)
     {
  -    String errMsg = getErrorMessage("ERROR: ", message, line, lineSrc, column);
  -    System.out.print(errMsg);
  +      String errMsg = getErrorMessage("msg.error", message, 
  +                                   sourceName, line, lineSrc, column);
  +      System.err.println(errMsg);
  +      logger.error(errMsg);
     }
   
     public void warning(String message, String sourceName, int line,
  -                      String lineSrc, int column)
  +                   String lineSrc, int column)
     {
  -    System.out.print(getErrorMessage("WARNING: ", message, line, lineSrc, column));
  +      String errMsg = getErrorMessage("msg.warning", message, 
  +                                 sourceName, line, lineSrc, column);
  +      System.err.println(errMsg);
  +      logger.warn(errMsg);
     }
       
     public EvaluatorException runtimeError(String message, String sourceName,
                                            int line, String lineSrc,
                                            int column)
     {
  -    String errMsg = getErrorMessage("", message, line, lineSrc, column);
  -    return new EvaluatorException(errMsg);
  +      return new EvaluatorException(getErrorMessage("msg.error", message,
  +                                                 sourceName, line,
  +                                                 lineSrc, column));
     }
   
     /**
  -   * Identifies the real location of the error in the file given the
  -   * information stored in <code>sourcesInfo</code>.
  +   * Formats error message
      *
      * @param type a <code>String</code> value, indicating the error
      * type (error or warning)
  @@ -75,50 +64,22 @@
      * message, with the source file and line number adjusted to the
      * real values
      */
  -  protected String getErrorMessage(String type,
  -                                   String message,
  -                                   int line,
  -                                   String lineSource, int column)
  -  {
  -    int i = 0, size = sourcesInfo.size();
  -    int accLines = 0;
  -
  -    // Find the file which contains the line number indicated by the error
  -    SourceInfo source;
  -    do {
  -      source = (SourceInfo)sourcesInfo.get(i);
  -      accLines += source.getLineNumbers();
  -      i++;
  -    } while (accLines < line && i < size);
  -
  -    String errorMsg;
  -
  -    if (i == size && line > accLines) {
  -      errorMsg = "ERROR: Line number " + line + " out of bounds!";
  -      return errorMsg;
  -    }
  -
  -    String systemId = source.getSystemId();
  -    int realLineNo = line - (accLines - source.getLineNumbers());
  -
  -    errorMsg = systemId + ":" + realLineNo;
  -
  -    // If line source information is provided, make use of that to
  -    // print a more descriptive error message.
  -    if (lineSource != null) {
  -      errorMsg += "\n\n" + lineSource + "\n";
  -
  -      StringBuffer blanks = new StringBuffer(column);
  -      for (i = 1; i < column; i++)
  -        blanks.append(" ");
  -
  -      errorMsg += blanks + "^" + "\n\n";
  +    String getErrorMessage(String type,
  +                        String message,
  +                        String sourceName, int line,
  +                        String lineSource, int column)
  +    {
  +     if (line > 0) {
  +         if (sourceName != null) {
  +             Object[] errArgs = { sourceName, new Integer(line), message };
  +             return ToolErrorReporter.getMessage("msg.format3", errArgs);
  +       } else {
  +           Object[] errArgs = { new Integer(line), message };
  +           return ToolErrorReporter.getMessage("msg.format2", errArgs);
  +            }
  +        } else {
  +            Object[] errArgs = { message };
  +            return ToolErrorReporter.getMessage("msg.format1", errArgs);
  +        }
       }
  -    else
  -      errorMsg += ": ";
  -
  -    errorMsg += type + message + "\n\n";
  -
  -    return errorMsg;
  -  }
   }
  
  
  
  1.2       +521 -537  
cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/JavaScriptInterpreter.java
  
  Index: JavaScriptInterpreter.java
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/JavaScriptInterpreter.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- JavaScriptInterpreter.java        9 Mar 2003 00:08:50 -0000       1.1
  +++ JavaScriptInterpreter.java        15 Mar 2003 09:56:04 -0000      1.2
  @@ -49,6 +49,7 @@
   import java.io.InputStream;
   import java.io.InputStreamReader;
   import java.io.Reader;
  +import java.util.Collections;
   import java.util.ArrayList;
   import java.util.HashMap;
   import java.util.Iterator;
  @@ -66,11 +67,13 @@
   import org.apache.cocoon.environment.ObjectModelHelper;
   import org.apache.cocoon.environment.Request;
   import org.apache.cocoon.environment.Session;
  +import org.apache.cocoon.ResourceNotFoundException;
   import org.apache.commons.jxpath.JXPathIntrospector;
   import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl;
   import org.apache.excalibur.source.Source;
   import org.mozilla.javascript.*;
   import org.mozilla.javascript.tools.debugger.ScopeProvider;
  +import org.mozilla.javascript.tools.ToolErrorReporter;
   
   /**
    * Interface with the JavaScript interpreter.
  @@ -80,546 +83,527 @@
    * @since March 25, 2002
    */
   public class JavaScriptInterpreter extends AbstractInterpreter
  -  implements Configurable, Initializable
  +    implements Configurable, Initializable
   {
  -  public static final String USER_GLOBAL_SCOPE = "JavaScript GLOBAL SCOPE";
  +    public static final String USER_GLOBAL_SCOPE = "JavaScript GLOBAL SCOPE";
   
  -  // This is the only optimization level that supports continuations
  -  // 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 [EMAIL PROTECTED] #reloadScripts} is true.
  -   */
  -  protected long lastTimeCheck = 0;
  -  JSGlobal scope;
  -  List compiledScripts = new ArrayList();
  -  JSErrorReporter errorReporter;
  -  boolean enableDebugger = false;
  -  org.mozilla.javascript.tools.debugger.Main debugger;
  -
  -  public void configure(Configuration config)
  -    throws ConfigurationException
  -  {
  -    super.configure(config);
  -
  -    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");
  -      }
  -
  -      final org.mozilla.javascript.tools.debugger.Main db
  -          = new org.mozilla.javascript.tools.debugger.Main("Cocoon Flow Debugger");
  -      db.pack();
  -      db.setSize(600,460);
  -      db.setExitAction(
  -        new Runnable() { public void run() { db.setVisible(false); } }
  -      );
  -      db.setVisible(true);
  -      debugger = db;
  -      Context.addContextListener(debugger);
  -      debugger.doBreak();
  -    }
  -
  -    Context context = Context.enter();
  -    context.setOptimizationLevel(OPTIMIZATION_LEVEL);
  -    context.setGeneratingDebug(true);
  -    // add support for Rhino objects to JXPath
  -    JXPathIntrospector.registerDynamicClass(org.mozilla.javascript.Scriptable.class,
  -                                    ScriptablePropertyHandler.class);
  -    JXPathContextReferenceImpl.addNodePointerFactory(new 
ScriptablePointerFactory());
  -
  -    try {
  -      scope = new JSGlobal(context);
  -
  -      // Register some handy classes with JavaScript, so we can make
  -      // use of them from the flow layer.
  -
  -      // Access to the Cocoon log
  -      ScriptableObject.defineClass(scope, JSLog.class);
  -
  -      // Access to Cocoon internal objects
  -      ScriptableObject.defineClass(scope, JSCocoon.class);
  -
  -      // Wrapper for WebContinuation
  -      ScriptableObject.defineClass(scope, JSWebContinuation.class);
  -
  -      // Define some functions on the top level scope
  -      String[] names = { "print" };
  -      try {
  -        ((ScriptableObject)scope)
  -          .defineFunctionProperties(names, JSGlobal.class,
  -                                    ScriptableObject.DONTENUM);
  -      }
  -      catch (PropertyException e) {
  -        throw new Error(e.getMessage());
  -      }
  -
  -      // Define some global variables in JavaScript
  -      Object args[] = {};
  -      Scriptable log = context.newObject(scope, "Log", args);
  -      ((JSLog)log).enableLogging(getLogger());
  -      scope.put("log", scope, log);
  -    }
  -    catch (Exception e) {
  -      Context.exit();
  -      e.printStackTrace();
  -      throw e;
  -    }
  -  }
  -
  -  /**
  -   * Returns the JavaScript scope, a Scriptable object, from the user
  -   * session instance. Each URI prefix, as returned by the [EMAIL PROTECTED]
  -   * org.apache.cocoon.environment.Environment#getURIPrefix} method,
  -   * can have a scope associated with it.
  -   *
  -   * @param environment an <code>Environment</code> value
  -   * @param createSession a <code>boolean</code> value
  -   * @return a <code>Scriptable</code> value
  -   */
  -  public Scriptable getSessionScope(Environment environment)
  -  {
  -    Map objectModel = environment.getObjectModel();
  -    Request request = ObjectModelHelper.getRequest(objectModel);
  -    Session session = request.getSession(false);
  -
  -    if (session == null) {
  -      return null;
  -    }
  -
  -    Scriptable scope;
  -    HashMap userScopes = (HashMap)session.getAttribute(USER_GLOBAL_SCOPE);
  -
  -    if (userScopes == null) {
  -      return null;
  -    }
  -
  -    scope = (Scriptable)userScopes.get(environment.getURIPrefix());
  -
  -    return scope;
  -  }
  -
  -  /**
  -   * Associates a JavaScript scope, a Scriptable object, with the URI
  -   * prefix of the current sitemap, as returned by the [EMAIL PROTECTED]
  -   * org.apache.cocoon.environment.Environment#getURIPrefix} method.
  -   *
  -   * @param environment an <code>Environment</code> value
  -   * @param scope a <code>Scriptable</code> value
  -   */
  -  public void setSessionScope(Environment environment, Scriptable scope)
  -  {
  -    Map objectModel = environment.getObjectModel();
  -    Request request = ObjectModelHelper.getRequest(objectModel);
  -    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);
  -    }
  -
  -    userScopes.put(environment.getURIPrefix(), scope);
  -  }
  -
  -  public void removeSessionScope(Environment environment)
  -  {
  -    Map objectModel = environment.getObjectModel();
  -    Request request = ObjectModelHelper.getRequest(objectModel);
  -    Session session = request.getSession(true);
  -
  -    HashMap userScopes = (HashMap)session.getAttribute(USER_GLOBAL_SCOPE);
  -    if (userScopes == null)
  -      return;
  -
  -    userScopes.remove(environment.getURIPrefix());
  -  }
  -
  -  /**
  -   * 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 invoke from the JavaScript
  -   * script <code>cocoon.createSession()</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
  -   * callFunction().</p>
  -   *
  -   * @param environment an <code>Environment</code> value
  -   * @param createNew a <code>boolean</code> value
  -   * @return a <code>Scriptable</code> value
  -   * @exception Exception if an error occurs
  -   */
  -  protected Scriptable enterContext(Environment environment)
  -    throws Exception
  -  {
  -    Context context = Context.enter();
  -    context.setOptimizationLevel(OPTIMIZATION_LEVEL);
  -    context.setGeneratingDebug(true);
  -    context.setCompileFunctionsWithDynamicScope(true);
  -    context.setErrorReporter(errorReporter);
  -    Scriptable thrScope = null;
  -
  -    // 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.
  -    thrScope = getSessionScope(environment);
  -
  -    // The Cocoon object exported to JavaScript needs to be setup here
  -    JSCocoon cocoon;
  -
  -    if (thrScope == null) {
  -      thrScope = context.newObject(scope);
  -
  -      thrScope.setPrototype(scope);
  -      // We want 'thrScope' to be a new top-level scope, so set its
  -      // parent scope to null. This means that any variables created
  -      // by assignments will be properties of "thrScope".
  -      thrScope.setParentScope(null);
  -
  -      // Put in the thread scope the Cocoon object, which gives access
  -      // to the interpreter object, and some Cocoon objects. See
  -      // JSCocoon for more details.
  -      Object args[] = {};
  -      cocoon = (JSCocoon)context.newObject(scope, "Cocoon", args);
  -      ((JSCocoon)cocoon).setInterpreter(this);
  -      ((JSCocoon)cocoon).setScope(thrScope);
  -      thrScope.put("cocoon", thrScope, cocoon);
  -
  -      Iterator iter = compiledScripts.iterator();
  -      while (iter.hasNext()) {
  -      Script compiledScript = (Script)iter.next();
  -      compiledScript.exec(context, thrScope);
  -      }
  -    } else {
  -      cocoon = (JSCocoon)thrScope.get("cocoon", thrScope);
  -    }
  -
  -    // We need to setup the JSCocoon object according to the current
  -    // request. Everything else remains the same.
  -    cocoon.setContext(manager, environment);
  -
  -    return thrScope;
  -  }
  -
  -  /**
  -   * Remove the Cocoon object from the JavaScript thread scope so it
  -   * can be garbage collected, together with all the objects it
  -   * contains.
  -   */
  -  protected void exitContext(Scriptable thrScope)
  -  {
  -      // thrScope may be null if an exception occurred compiling a script
  -      if (thrScope != null) { 
  -       JSCocoon cocoon = (JSCocoon)thrScope.get("cocoon", thrScope);
  -       cocoon.invalidateContext();
  -      }
  -      Context.exit();
  -  }
  -
  -  public void readScripts(Environment environment, List sources)
  -    throws Exception
  -  {
  -    Scriptable thrScope = null;
  -
  -    if (getLogger().isDebugEnabled()) {
  -        getLogger().debug("Reading scripts");
  -    }
  -
  -    try {
  -      thrScope = enterContext(environment);
  -      Iterator iter = sources.iterator();
  -      while (iter.hasNext()) {
  -          Source src = (Source)iter.next();
  -          InputStream is = src.getInputStream();
  -          Reader reader = new BufferedReader(new InputStreamReader(is));
  -          Context context = Context.getCurrentContext();
  -          Script compiledScript = context.compileReader(thrScope, reader,
  -                                                        src.getURI(), 
  -                                                        1, null);
  -          compiledScripts.add(compiledScript);
  -      }
  -    }
  -    catch (JavaScriptException ex) {
  -      Object value = ex.getValue();
  -      while (value instanceof Wrapper) {
  -       value = ((Wrapper)value).unwrap();
  -      }
  -      if (value instanceof Exception) {
  -       Exception e = (Exception)value;
  -       e.printStackTrace();
  -       throw e;
  -      } else if (value instanceof Error) {
  -       throw (Error)value;
  -      }
  -      throw ex;
  -    } catch (Exception ex) {
  -      ex.printStackTrace();
  -      throw ex;
  -    }
  -    finally {
  -      exitContext(thrScope);
  -    }
  -  }
  -
  -  /**
  -   * 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);
  -        src.refresh();
  -        getLogger().debug("Checking " + src.getURI()
  -                           + ", source " + src
  -                           + ", last modified " + src.getLastModified()
  -                           + ", last time check " + lastTimeCheck);
  -        if (src.getLastModified() > lastTimeCheck) {
  -          needsRefresh = true;
  -          break;
  -        }
  -      }
  -    }
  -
  -    // FIXME: remove the need for synchronization
  -    synchronized (this) {
  -      int size = needResolve.size();
  -
  -      // If there's no need to re-read any file, and no files
  -      // have been requested to be read since the last time,
  -      // don't do anything.
  -      if (!needsRefresh && size == 0) {
  +    // This is the only optimization level that supports continuations
  +    // 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 [EMAIL PROTECTED] #reloadScripts} is true.
  +     */
  +    protected long lastTimeCheck = 0;
  +    JSGlobal scope;
  +    List compiledScripts = Collections.synchronizedList(new ArrayList());
  +    JSErrorReporter errorReporter;
  +    boolean enableDebugger = false;
  +    org.mozilla.javascript.tools.debugger.Main debugger;
  +
  +    public void configure(Configuration config)
  +        throws ConfigurationException
  +    {
  +        super.configure(config);
  +
  +        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");
  +            }
  +
  +            final org.mozilla.javascript.tools.debugger.Main db
  +                = new org.mozilla.javascript.tools.debugger.Main("Cocoon Flow 
Debugger");
  +            db.pack();
  +            db.setSize(600,460);
  +            db.setExitAction(new Runnable() { 
  +                    public void run() { 
  +                        db.setVisible(false); 
  +                    } 
  +                });
  +            db.setVisible(true);
  +            debugger = db;
  +            Context.addContextListener(debugger);
  +            debugger.doBreak();
  +        }
  +
  +        Context context = Context.enter();
  +        context.setOptimizationLevel(OPTIMIZATION_LEVEL);
  +        context.setGeneratingDebug(true);
  +        // add support for Rhino objects to JXPath
  +        
JXPathIntrospector.registerDynamicClass(org.mozilla.javascript.Scriptable.class,
  +                                                ScriptablePropertyHandler.class);
  +        JXPathContextReferenceImpl.addNodePointerFactory(new 
ScriptablePointerFactory());
  +
  +        try {
  +            scope = new JSGlobal(context);
  +
  +            // Register some handy classes with JavaScript, so we can make
  +            // use of them from the flow layer.
  +
  +            // Access to the Cocoon log
  +            ScriptableObject.defineClass(scope, JSLog.class);
  +
  +            // Access to Cocoon internal objects
  +            ScriptableObject.defineClass(scope, JSCocoon.class);
  +
  +            // Wrapper for WebContinuation
  +            ScriptableObject.defineClass(scope, JSWebContinuation.class);
  +
  +            // Define some functions on the top level scope
  +            String[] names = { "print" };
  +            try {
  +                ((ScriptableObject)scope)
  +                    .defineFunctionProperties(names, JSGlobal.class,
  +                                              ScriptableObject.DONTENUM);
  +            }
  +            catch (PropertyException e) {
  +                throw new Error(e.getMessage());
  +            }
  +
  +            // Define some global variables in JavaScript
  +            Object args[] = {};
  +            Scriptable log = context.newObject(scope, "Log", args);
  +            ((JSLog)log).enableLogging(getLogger());
  +            scope.put("log", scope, log);
  +            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 URI prefix, as returned by the [EMAIL PROTECTED]
  +     * org.apache.cocoon.environment.Environment#getURIPrefix} method,
  +     * can have a scope associated with it.
  +     *
  +     * @param environment an <code>Environment</code> value
  +     * @param createSession a <code>boolean</code> value
  +     * @return a <code>Scriptable</code> value
  +     */
  +    public Scriptable getSessionScope(Environment environment)
  +    {
  +        Map objectModel = environment.getObjectModel();
  +        Request request = ObjectModelHelper.getRequest(objectModel);
  +        Session session = request.getSession(false);
  +
  +        if (session == null) {
  +            return null;
  +        }
  +
  +        Scriptable scope;
  +        HashMap userScopes = (HashMap)session.getAttribute(USER_GLOBAL_SCOPE);
  +
  +        if (userScopes == null) {
  +            return null;
  +        }
  +
  +        scope = (Scriptable)userScopes.get(environment.getURIPrefix());
  +
  +        return scope;
  +    }
  +
  +    /**
  +     * Associates a JavaScript scope, a Scriptable object, with the URI
  +     * prefix of the current sitemap, as returned by the [EMAIL PROTECTED]
  +     * org.apache.cocoon.environment.Environment#getURIPrefix} method.
  +     *
  +     * @param environment an <code>Environment</code> value
  +     * @param scope a <code>Scriptable</code> value
  +     */
  +    public void setSessionScope(Environment environment, Scriptable scope)
  +    {
  +        Map objectModel = environment.getObjectModel();
  +        Request request = ObjectModelHelper.getRequest(objectModel);
  +        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);
  +        }
  +
  +        userScopes.put(environment.getURIPrefix(), scope);
  +    }
  +
  +    public void removeSessionScope(Environment environment)
  +    {
  +        Map objectModel = environment.getObjectModel();
  +        Request request = ObjectModelHelper.getRequest(objectModel);
  +        Session session = request.getSession(true);
  +
  +        HashMap userScopes = (HashMap)session.getAttribute(USER_GLOBAL_SCOPE);
  +        if (userScopes == null)
  +            return;
  +
  +        userScopes.remove(environment.getURIPrefix());
  +    }
  +
  +    /**
  +     * 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 invoke from the JavaScript
  +     * script <code>cocoon.createSession()</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
  +     * callFunction().</p>
  +     *
  +     * @param environment an <code>Environment</code> value
  +     * @param createNew a <code>boolean</code> value
  +     * @param sourcesToBeCompiled list of Source's to compile 
  +     * @return a <code>Scriptable</code> value
  +     * @exception Exception if an error occurs
  +     */
  +    protected Scriptable enterContext(Environment environment, 
  +                                      boolean needsExec,
  +                                      List sourcesToBeCompiled)
  +        throws Exception
  +    {
  +        Context context = Context.enter();
  +        context.setOptimizationLevel(OPTIMIZATION_LEVEL);
  +        context.setGeneratingDebug(true);
  +        context.setCompileFunctionsWithDynamicScope(true);
  +        context.setErrorReporter(errorReporter);
  +        Scriptable thrScope = null;
  +
  +        compileScripts(context, environment, sourcesToBeCompiled);
  +
  +        // Try to retrieve the scope object from the session instance. If
  +        // no scope is found, we create a new one, but don't place it in
  +        // 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.
  +        thrScope = getSessionScope(environment);
  +
  +        // The Cocoon object exported to JavaScript needs to be setup here
  +        JSCocoon cocoon;
  +        if (thrScope == null) {
  +            thrScope = context.newObject(scope);
  +
  +            thrScope.setPrototype(scope);
  +            // We want 'thrScope' to be a new top-level scope, so set its
  +            // parent scope to null. This means that any variables created
  +            // by assignments will be properties of "thrScope".
  +            thrScope.setParentScope(null);
  +
  +            // Put in the thread scope the Cocoon object, which gives access
  +            // to the interpreter object, and some Cocoon objects. See
  +            // JSCocoon for more details.
  +            Object args[] = {};
  +            cocoon = (JSCocoon)context.newObject(scope, "Cocoon", args);
  +            ((JSCocoon)cocoon).setInterpreter(this);
  +            ((JSCocoon)cocoon).setScope(thrScope);
  +            thrScope.put("cocoon", thrScope, cocoon);
  +            needsExec = true;
  +        } else {
  +            cocoon = (JSCocoon)thrScope.get("cocoon", thrScope);
  +        }
  +        // We need to setup the JSCocoon object according to the current
  +        // request. Everything else remains the same.
  +        cocoon.setContext(manager, environment);
  +
  +        if (needsExec) {
  +            for (int i = 0; i < compiledScripts.size(); i++) {
  +                Script compiledScript = (Script)compiledScripts.get(i);
  +                compiledScript.exec(context, thrScope);
  +            }
  +        }
  +
  +
  +        return thrScope;
  +    }
  +
  +    /**
  +     * Remove the Cocoon object from the JavaScript thread scope so it
  +     * can be garbage collected, together with all the objects it
  +     * contains.
  +     */
  +    protected void exitContext(Scriptable thrScope)
  +    {
  +        // thrScope may be null if an exception occurred compiling a script
  +        if (thrScope != null) { 
  +            JSCocoon cocoon = (JSCocoon)thrScope.get("cocoon", thrScope);
  +            cocoon.invalidateContext();
  +        }
  +        Context.exit();
  +    }
  +
  +    private void compileScripts(Context cx, Environment environment, List sources)
  +        throws Exception
  +    {
  +        if (getLogger().isDebugEnabled()) {
  +            getLogger().debug("Reading scripts");
  +        }
  +        Iterator iter = sources.iterator();
  +        while (iter.hasNext()) {
  +            Source src = (Source)iter.next();
  +            compileScript(cx, src);
  +        }
  +    }
  +
  +    /**
  +     * Compile filename as JavaScript code
  +     * @param cx Rhino context
  +     * @param environment source resolver
  +     * @param fileName resource uri
  +     * @return compiled script
  +     */
  +
  +    public Script compileScript(Context cx, 
  +                                Environment environment, 
  +                                String fileName) throws Exception {
  +        Source src = environment.resolveURI(fileName);
  +        if (src == null) {
  +            throw new ResourceNotFoundException(fileName + ": not found");
  +        }
  +        return compileScript(cx, src);
  +    }
  +
  +    private Script compileScript(Context cx, Source src) throws Exception {
  +        InputStream is = src.getInputStream();
  +        Reader reader = new BufferedReader(new InputStreamReader(is));
  +        Script compiledScript = cx.compileReader(scope, reader,
  +                                                 src.getURI(), 
  +                                                 1, null);
  +        compiledScripts.add(compiledScript);
  +        return compiledScript;
  +    }
  +
  +    /**
  +     * Reloads any modified script files.
  +     *
  +     * <p>It checks to see if any of the files already read in (those
  +     * present in the <code>scripts</code> hash map) have been
  +     * modified.
  +     *
  +     * <p>It also checks to see if any script files have been registered
  +     * with the interpreter since the last call to
  +     * <code>checkForModifiedScripts</code>. These files are stored in
  +     * the temporary array <code>needResolve</code>. If any such files
  +     * are found, they are read in.
  +     *
  +     * @param environment an <code>Environment</code> value
  +     * @param toBeCompiled output parameter: the list of <code>Source</code> 
objects to be compiled
  +     * @return true if any existing Source script has changed
  +     */
  +    public boolean checkForModifiedScripts(Environment environment, 
  +                                           List toBeCompiled)
  +        throws Exception
  +    {
  +        boolean needsRefresh = false;
  +        if (reloadScripts
  +            && System.currentTimeMillis() >= lastTimeCheck + checkTime) {
  +            // FIXME: should we worry about synchronization?
  +            for (int i = 0, size = scripts.size(); i < size; i++) {
  +                Source src = (Source)scripts.get(i);
  +                src.refresh();
  +                getLogger().debug("Checking " + src.getURI()
  +                                  + ", source " + src
  +                                  + ", last modified " + src.getLastModified()
  +                                  + ", last time check " + lastTimeCheck);
  +                if (src.getLastModified() > lastTimeCheck) {
  +                    needsRefresh = true;
  +                    break;
  +                }
  +            }
  +        }
  +        
  +        // FIXME: remove the need for synchronization
  +        synchronized (this) {
  +            int size = needResolve.size();
  +            
  +            // If there's no need to re-read any file, and no files
  +            // have been requested to be read since the last time,
  +            // don't do anything.
  +            if (!needsRefresh && size == 0) {
  +                lastTimeCheck = System.currentTimeMillis();
  +                return false;
  +            }
  +            
  +            for (int i = 0; i < size; i++) {
  +                String source = (String)needResolve.get(i);
  +                Source src = environment.resolveURI(source);
  +                scripts.add(src);
  +                toBeCompiled.add(src);
  +            }
  +            needResolve.clear();
  +        }
  +        
  +        // Update the time of the last check. If an exception occurs, this
  +        // is not executed, so the next request will force a reparse of
  +        // the script files because of an old time stamp.
           lastTimeCheck = System.currentTimeMillis();
  -        return;
  -      }
  +        return needsRefresh;
  +    }
  +    
  +    /**
  +     * 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 environment an <code>Environment</code> value
  +     * @exception Exception if an error occurs
  +     */
  +    public void callFunction(String funName, List params,
  +                             Environment environment)
  +        throws Exception
  +    {
  +        Scriptable thrScope = null;
  +        List toBeCompiled = new ArrayList(); 
  +        boolean needsRefresh = checkForModifiedScripts(environment, toBeCompiled);
  +        try {
  +            thrScope = enterContext(environment, needsRefresh, toBeCompiled);
  +
  +            Context context = Context.getCurrentContext();
  +            JSCocoon cocoon = (JSCocoon)thrScope.get("cocoon", thrScope);
  +          
  +            if (enableDebugger) {
  +                final Scriptable s = thrScope;
  +                debugger.setScopeProvider(
  +                                          new ScopeProvider()
  +                                              { public Scriptable getScope() 
{return s;} }
  +                                          );
  +                if (!debugger.isVisible())
  +                    debugger.setVisible(true);
  +            }
  +          
  +            Object callFunction = thrScope.get("callFunction", thrScope);
  +            if (callFunction == Scriptable.NOT_FOUND)
  +                throw new RuntimeException("Cannot find 'callFunction' "
  +                                           + "(system.js not loaded?)");
  +          
  +            Object fun = thrScope.get(funName, thrScope);
  +            if (fun == Scriptable.NOT_FOUND)
  +                throw new RuntimeException("'" + funName + "' is undefined!");
  +            if (!(fun instanceof Function))
  +                throw new RuntimeException("'" + funName + "' is not a function!");
  +          
  +            int size = (params != null ? params.size() : 0);
  +            Object[] funArgs = new Object[size];
  +            NativeArray parameters = new NativeArray(size);
  +            if (size != 0) {
  +                for (int i = 0; i < size; i++) {
  +                    Interpreter.Argument arg = (Interpreter.Argument)params.get(i);
  +                    funArgs[i] = arg.value;
  +                    parameters.put(arg.name, parameters, arg.value);
  +                }
  +            }
  +            cocoon.setParameters(parameters);
  +            NativeArray funArgsArray = new NativeArray(funArgs);
  +            Object callFunArgs[] = { fun, funArgsArray };
  +            ((Function) callFunction).call(context, thrScope, thrScope, 
callFunArgs);
  +        }
  +        catch (JavaScriptException ex) {
  +            
Context.reportError(ToolErrorReporter.getMessage("msg.uncaughtJSException",
  +                                                             ex.getMessage()));
  +            throw ex;
  +        }
  +        finally {
  +            exitContext(thrScope);
  +        }
  +    }
  +
  +    public void handleContinuation(String id, List params,
  +                                   Environment environment)
  +        throws Exception
  +    {
  +        WebContinuation wk = continuationsMgr.lookupWebContinuation(id);
  +
  +        if (wk == null) {
  +            List p = new ArrayList();
  +            p.add(new Interpreter.Argument("kontId", id));
  +            callFunction("handleInvalidContinuation", p, environment);
  +            return;
  +        }
   
  -      for (int i = 0; i < size; i++) {
  -        String source = (String)needResolve.get(i);
  -        Source src = environment.resolveURI(source);
  -        scripts.add(src);
  -      }
  -      needResolve.clear();
  -      //ListInputStream is = new ListInputStream(scripts);
  -      //errorReporter = new JSErrorReporter(is.getSourceInfo());
  -      readScripts(environment, scripts);
  -    }
  -
  -    // 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();
  -  }
  -
  -  /**
  -   * 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 environment an <code>Environment</code> value
  -   * @exception Exception if an error occurs
  -   */
  -  public void callFunction(String funName, List params,
  -                           Environment environment)
  -    throws Exception
  -  {
  -    Scriptable thrScope = null;
  -
  -    checkForModifiedScripts(environment);
  -
  -    try {
  -      thrScope = enterContext(environment);
  -      Context context = Context.getCurrentContext();
  -      JSCocoon cocoon = (JSCocoon)thrScope.get("cocoon", thrScope);
  -
  -      if (enableDebugger) {
  -        final Scriptable s = thrScope;
  -        debugger.setScopeProvider(
  -            new ScopeProvider()
  -            { public Scriptable getScope() {return s;} }
  -        );
  -        if (!debugger.isVisible())
  -            debugger.setVisible(true);
  -      }
  -
  -      Object callFunction = thrScope.get("callFunction", thrScope);
  -      if (callFunction == Scriptable.NOT_FOUND)
  -        throw new RuntimeException("Cannot find 'callFunction' "
  -                                   + "(system.js not loaded?)");
  -
  -      Object fun = thrScope.get(funName, thrScope);
  -      if (fun == Scriptable.NOT_FOUND)
  -        throw new RuntimeException("'" + funName + "' is undefined!");
  -      if (!(fun instanceof Function))
  -        throw new RuntimeException("'" + funName + "' is not a function!");
  -
  -      int size = (params != null ? params.size() : 0);
  -      Object[] funArgs = new Object[size];
  -      NativeArray parameters = new NativeArray(size);
  -      if (size != 0) {
  -        for (int i = 0; i < size; i++) {
  -          Interpreter.Argument arg = (Interpreter.Argument)params.get(i);
  -       funArgs[i] = arg.value;
  -          parameters.put(arg.name, parameters, arg.value);
  -        }
  -      }
  -      cocoon.setParameters(parameters);
  -      NativeArray funArgsArray = new NativeArray(funArgs);
  -      Object callFunArgs[] = { fun, funArgsArray };
  -      ((Function) callFunction).call(context, thrScope, thrScope, callFunArgs);
  -    }
  -    catch (JavaScriptException ex) {
  -      Object value = ex.getValue();
  -      while (value instanceof Wrapper) {
  -       value = ((Wrapper)value).unwrap();
  -      }
  -      if (value instanceof Exception) {
  -       Exception e = (Exception)value;
  -       e.printStackTrace();
  -       throw e;
  -      } else if (value instanceof Error) {
  -       throw (Error)value;
  -      }
  -      throw ex;
  -    }
  -    catch (Exception ex) {
  -     ex.printStackTrace();
  -     throw ex;
  -    }
  -    finally {
  -      exitContext(thrScope);
  -    }
  -  }
  -
  -  public void handleContinuation(String id, List params,
  -                                 Environment environment)
  -    throws Exception
  -  {
  -    WebContinuation wk = continuationsMgr.lookupWebContinuation(id);
  -
  -    if (wk == null) {
  -      List p = new ArrayList();
  -      p.add(new Interpreter.Argument("kontId", id));
  -      callFunction("handleInvalidContinuation", p, environment);
  -      return;
  -    }
  -
  -    Context context = Context.enter();
  -    context.setOptimizationLevel(OPTIMIZATION_LEVEL);
  -    context.setGeneratingDebug(true);
  -    context.setCompileFunctionsWithDynamicScope(true);
  -
  -    // Obtain the JS continuation object from it, and setup the
  -    // JSCocoon object associated in the dynamic scope of the saved
  -    // continuation with the environment and context objects.
  -    JSWebContinuation jswk = (JSWebContinuation)wk.getUserObject();
  -    JSCocoon cocoon = jswk.getJSCocoon();
  -    cocoon.setContext(manager, environment);
  -    final Scriptable kScope = cocoon.getScope();
  -
  -    if (enableDebugger) {
  -      debugger.setScopeProvider(
  -        new ScopeProvider()
  -          { public Scriptable getScope() {return kScope;} }
  -      );
  -      if (!debugger.isVisible())
  -          debugger.setVisible(true);
  -    }
  -
  -    // We can now resume the processing from the state saved by the
  -    // continuation object. Setup the JavaScript Context object.
  -    Object handleContFunction = kScope.get("handleContinuation", kScope);
  -    if (handleContFunction == Scriptable.NOT_FOUND)
  -      throw new RuntimeException("Cannot find 'handleContinuation' "
  -                                 + "(system.js not loaded?)");
  -
  -    Object args[] = { jswk };
  -
  -    int size = (params != null ? params.size() : 0);
  -    NativeArray parameters = new NativeArray(size);
  -
  -    if (size != 0) {
  -      for (int i = 0; i < size; i++) {
  -        Interpreter.Argument arg = (Interpreter.Argument)params.get(i);
  -        parameters.put(arg.name, parameters, arg.value);
  -      }
  -    }
  -
  -    cocoon.setParameters(parameters);
  -
  -    try {
  -      ((Function)handleContFunction).call(context, kScope, kScope, args);
  -    } catch (JavaScriptException ex) {
  -      Object value = ex.getValue();
  -      while (value instanceof Wrapper) {
  -        value = ((Wrapper)value).unwrap();
  -      }
  -      if (value instanceof Exception) {
  -        Exception e = (Exception)value;
  -        e.printStackTrace();
  -        throw e;
  -      } else if (value instanceof Error) {
  -        throw (Error)value;
  -      }
  -      throw ex;
  -    } catch (Exception ex) {
  -      ex.printStackTrace();
  -      throw ex;
  -    } finally {
  -      Context.exit();
  +        Context context = Context.enter();
  +        context.setOptimizationLevel(OPTIMIZATION_LEVEL);
  +        context.setGeneratingDebug(true);
  +        context.setCompileFunctionsWithDynamicScope(true);
  +
  +        // Obtain the JS continuation object from it, and setup the
  +        // JSCocoon object associated in the dynamic scope of the saved
  +        // continuation with the environment and context objects.
  +        JSWebContinuation jswk = (JSWebContinuation)wk.getUserObject();
  +        JSCocoon cocoon = jswk.getJSCocoon();
  +        cocoon.setContext(manager, environment);
  +        final Scriptable kScope = cocoon.getScope();
  +
  +        if (enableDebugger) {
  +            debugger.setScopeProvider(
  +                                      new ScopeProvider()
  +                                          { public Scriptable getScope() {return 
kScope;} }
  +                                      );
  +            if (!debugger.isVisible())
  +                debugger.setVisible(true);
  +        }
  +
  +        // We can now resume the processing from the state saved by the
  +        // continuation object. Setup the JavaScript Context object.
  +        Object handleContFunction = kScope.get("handleContinuation", kScope);
  +        if (handleContFunction == Scriptable.NOT_FOUND)
  +            throw new RuntimeException("Cannot find 'handleContinuation' "
  +                                       + "(system.js not loaded?)");
  +
  +        Object args[] = { jswk };
  +
  +        int size = (params != null ? params.size() : 0);
  +        NativeArray parameters = new NativeArray(size);
  +
  +        if (size != 0) {
  +            for (int i = 0; i < size; i++) {
  +                Interpreter.Argument arg = (Interpreter.Argument)params.get(i);
  +                parameters.put(arg.name, parameters, arg.value);
  +            }
  +        }
  +
  +        cocoon.setParameters(parameters);
  +
  +        try {
  +            ((Function)handleContFunction).call(context, kScope, kScope, args);
  +        } catch (JavaScriptException ex) {
  +            
Context.reportError(ToolErrorReporter.getMessage("msg.uncaughtJSException",
  +                                                             ex.getMessage()));
  +            throw ex;
  +        } finally {
  +            Context.exit();
  +        }
       }
  -  }
   }
  
  
  
  1.2       +24 -15    
cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/ScriptableConnection.java
  
  Index: ScriptableConnection.java
  ===================================================================
  RCS file: 
/home/cvs/cocoon-2.1/src/java/org/apache/cocoon/components/flow/javascript/ScriptableConnection.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ScriptableConnection.java 9 Mar 2003 00:08:50 -0000       1.1
  +++ ScriptableConnection.java 15 Mar 2003 09:56:04 -0000      1.2
  @@ -123,7 +123,6 @@
                       return fun.has(index, start);
                   }
   
  -
                   public void put(String name, Scriptable start, Object value) {
                       fun.put(name, start, value);
                   }
  @@ -208,23 +207,33 @@
   
       public Object jsFunction_query(String sql, 
                                      int startRow, 
  -                                   int maxRows) throws Exception {
  -        Statement stmt = connection.createStatement();
  -        ResultSet rs = stmt.executeQuery(sql);
  -        if (maxRows == 0) {
  -            maxRows = -1;
  +                                   int maxRows) 
  +        throws JavaScriptException {
  +        try {
  +            Statement stmt = connection.createStatement();
  +            ResultSet rs = stmt.executeQuery(sql);
  +            if (maxRows == 0) {
  +                maxRows = -1;
  +            }
  +            ScriptableResult s = new ScriptableResult(this, rs, 
  +                                                      startRow, maxRows);
  +            s.setParentScope(getTopLevelScope(this));
  +            s.setPrototype(getClassPrototype(this, s.getClassName()));
  +            return s;
  +        } catch (Exception e) {
  +            throw new JavaScriptException(e);
           }
  -        ScriptableResult s = new ScriptableResult(this, rs, 
  -                                                  startRow, maxRows);
  -        s.setParentScope(getTopLevelScope(this));
  -        s.setPrototype(getClassPrototype(this, s.getClassName()));
  -        return s;
       }
   
  -    public int jsFunction_update(String sql) throws Exception {
  -        Statement stmt = connection.createStatement();
  -        stmt.execute(sql);
  -        return stmt.getUpdateCount();
  +    public int jsFunction_update(String sql) 
  +        throws JavaScriptException {
  +        try {
  +            Statement stmt = connection.createStatement();
  +            stmt.execute(sql);
  +            return stmt.getUpdateCount();
  +        } catch (Exception e) {
  +            throw new JavaScriptException(e);
  +        }
       }
   
       public Object get(String name, Scriptable start) {
  
  
  

Reply via email to