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]