Author: vgritsenko Date: Thu Nov 11 18:28:23 2004 New Revision: 57490 Modified: cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/fom/FOM_JavaScriptInterpreter.java cocoon/trunk/status.xml Log: deprecate flow functions parameters support... remove flow functions parameters support... port rest of the changes from branch: release source resolver, add FIXME, code tweaks.
Modified: cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/fom/FOM_JavaScriptInterpreter.java ============================================================================== --- cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/fom/FOM_JavaScriptInterpreter.java (original) +++ cocoon/trunk/src/java/org/apache/cocoon/components/flow/javascript/fom/FOM_JavaScriptInterpreter.java Thu Nov 11 18:28:23 2004 @@ -15,29 +15,13 @@ */ package org.apache.cocoon.components.flow.javascript.fom; -import java.awt.Dimension; -import java.awt.Toolkit; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.Reader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; - import org.apache.avalon.framework.CascadingRuntimeException; 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.avalon.framework.service.ServiceManager; + import org.apache.cocoon.ProcessingException; import org.apache.cocoon.ResourceNotFoundException; import org.apache.cocoon.components.ContextHelper; @@ -52,6 +36,7 @@ import org.apache.cocoon.environment.Redirector; import org.apache.cocoon.environment.Request; import org.apache.cocoon.environment.Session; + import org.apache.commons.jxpath.JXPathIntrospector; import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl; import org.apache.excalibur.source.Source; @@ -76,6 +61,23 @@ import org.mozilla.javascript.tools.debugger.Main; import org.mozilla.javascript.tools.shell.Global; +import java.awt.Dimension; +import java.awt.Toolkit; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.Reader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; + /** * Interface with the JavaScript interpreter. * @@ -98,37 +100,38 @@ /** * Prefix for session/request attribute storing JavaScript global scope object. */ - public static final String USER_GLOBAL_SCOPE = "FOM JavaScript GLOBAL SCOPE/"; + private static final String USER_GLOBAL_SCOPE = "FOM JavaScript GLOBAL SCOPE/"; - // This is the only optimization level that supports continuations - // in the Christoper Oliver's Rhino JavaScript implementation - static int OPTIMIZATION_LEVEL = -2; + /** + * This is the only optimization level that supports continuations + * in the Christoper Oliver's Rhino JavaScript implementation + */ + private static final int OPTIMIZATION_LEVEL = -2; /** * When was the last time we checked for script modifications. Used * only if [EMAIL PROTECTED] #reloadScripts} is true. */ - protected long lastTimeCheck = 0; + private long lastTimeCheck; /** * Shared global scope for scripts and other immutable objects */ - Global scope; - - CompilingClassLoader classLoader; + private Global scope; - MyClassRepository javaClassRepository = new MyClassRepository(); - - String[] javaSourcePath; + // FIXME: Does not belong here, should be moved into the sitemap or even higher? + private CompilingClassLoader classLoader; + private MyClassRepository javaClassRepository = new MyClassRepository(); + private String[] javaSourcePath; /** * List of <code>String</code> objects that represent files to be * read in by the JavaScript interpreter. */ - List topLevelScripts = new ArrayList(); + private List topLevelScripts = new ArrayList(); - JSErrorReporter errorReporter; - boolean enableDebugger = false; + private JSErrorReporter errorReporter; + private boolean enableDebugger; /** * Needed to get things working with JDK 1.3. Can be removed once we @@ -139,7 +142,6 @@ } class MyClassRepository implements CompilingClassLoader.ClassRepository { - Map javaSource = new HashMap(); Map javaClass = new HashMap(); Map sourceToClass = new HashMap(); @@ -166,45 +168,48 @@ public synchronized boolean upToDateCheck() throws Exception { SourceResolver sourceResolver = (SourceResolver) getServiceManager().lookup(SourceResolver.ROLE); - Iterator iter = javaSource.entrySet().iterator(); - List invalid = new LinkedList(); - while (iter.hasNext()) { - Map.Entry e = (Map.Entry)iter.next(); - String uri = (String)e.getKey(); - SourceValidity validity = - (SourceValidity)e.getValue(); - int valid = validity.isValid(); - if (valid == SourceValidity.UNKNOWN) { - Source newSrc = null; - try { - newSrc = sourceResolver.resolveURI(uri); - valid = newSrc.getValidity().isValid(validity); - } catch (Exception ignored) { - } finally { - if (newSrc != null) { - sourceResolver.release(newSrc); + try { + List invalid = new LinkedList(); + for (Iterator i = javaSource.entrySet().iterator(); i.hasNext();) { + Map.Entry e = (Map.Entry) i.next(); + String uri = (String) e.getKey(); + SourceValidity validity = (SourceValidity) e.getValue(); + int valid = validity.isValid(); + if (valid == SourceValidity.UNKNOWN) { + Source newSrc = null; + try { + newSrc = sourceResolver.resolveURI(uri); + valid = newSrc.getValidity().isValid(validity); + } catch (Exception ignored) { + } finally { + if (newSrc != null) { + sourceResolver.release(newSrc); + } } } + if (valid != SourceValidity.VALID) { + invalid.add(uri); + } } - if (valid != SourceValidity.VALID) { - invalid.add(uri); - } - } - iter = invalid.iterator(); - while (iter.hasNext()) { - String uri = (String)iter.next(); - Set set = (Set)sourceToClass.get(uri); - Iterator ii = set.iterator(); - while (ii.hasNext()) { - String className = (String)ii.next(); - sourceToClass.remove(className); - javaClass.remove(className); - classToSource.remove(className); + + for (Iterator i = invalid.iterator(); i.hasNext();) { + String uri = (String) i.next(); + Set set = (Set) sourceToClass.get(uri); + Iterator ii = set.iterator(); + while (ii.hasNext()) { + String className = (String) ii.next(); + sourceToClass.remove(className); + javaClass.remove(className); + classToSource.remove(className); + } + set.clear(); + javaSource.remove(uri); } - set.clear(); - javaSource.remove(uri); + + return invalid.size() == 0; + } finally { + getServiceManager().release(sourceResolver); } - return invalid.size() == 0; } } @@ -212,7 +217,7 @@ * JavaScript debugger: there's only one of these: it can debug multiple * threads executing JS code. */ - static Main debugger; + private static Main debugger; static synchronized Main getDebugger() { if (debugger == null) { @@ -238,16 +243,13 @@ public void configure(Configuration config) throws ConfigurationException { super.configure(config); - String loadOnStartup - = config.getChild("load-on-startup", true).getValue(null); + String loadOnStartup = config.getChild("load-on-startup").getValue(null); if (loadOnStartup != null) { register(loadOnStartup); } String debugger = config.getChild("debugger").getValue(null); - if ("enabled".equalsIgnoreCase(debugger)) { - enableDebugger = true; - } + enableDebugger = "enabled".equalsIgnoreCase(debugger); if (reloadScripts) { String classPath = config.getChild("classpath").getValue(null); @@ -300,15 +302,18 @@ if (!reloadScripts) { return Thread.currentThread().getContextClassLoader(); } + synchronized (javaClassRepository) { boolean reload = needsRefresh || classLoader == null; if (needsRefresh && classLoader != null) { reload = !javaClassRepository.upToDateCheck(); } + if (reload) { + // FIXME FIXME FIXME Resolver not released! classLoader = new CompilingClassLoader( Thread.currentThread().getContextClassLoader(), - (SourceResolver)manager.lookup(SourceResolver.ROLE), + (SourceResolver) manager.lookup(SourceResolver.ROLE), javaClassRepository); classLoader.addSourceListener( new CompilingClassLoader.SourceListener() { @@ -316,11 +321,9 @@ // no action } - public void sourceCompilationError(Source src, - String errMsg) { - + public void sourceCompilationError(Source src, String msg) { if (src != null) { - throw Context.reportRuntimeError(errMsg); + throw Context.reportRuntimeError(msg); } } }); @@ -402,14 +405,41 @@ boolean locked = false; - public ThreadScope() { + /** + * Initializes new top-level scope. + */ + public ThreadScope(Global scope) throws Exception { + final Context context = Context.getCurrentContext(); + final String[] names = { "importClass" }; try { - defineFunctionProperties(names, ThreadScope.class, + defineFunctionProperties(names, + ThreadScope.class, ScriptableObject.DONTENUM); } catch (PropertyException e) { throw new Error(); // should never happen } + + setPrototype(scope); + + // We want this 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 this. + setParentScope(null); + + // Put in the thread scope the Cocoon object, which gives access + // to the interpreter object, and some Cocoon objects. See + // FOM_Cocoon for more details. + final Object[] args = {}; + FOM_Cocoon cocoon = (FOM_Cocoon) context.newObject(this, + "FOM_Cocoon", + args); + cocoon.setParentScope(this); + super.put("cocoon", this, cocoon); + + defineProperty(LAST_EXEC_TIME, + new Long(0), + ScriptableObject.DONTENUM | ScriptableObject.PERMANENT); } public String getClassName() { @@ -441,8 +471,10 @@ super.put(index, start, value); } - void reset() { + // Invoked after script execution + void onExec() { this.useSession = false; + super.put(LAST_EXEC_TIME, this, new Long(System.currentTimeMillis())); } /** Override importClass to allow reloading of classes */ @@ -486,29 +518,7 @@ } private ThreadScope createThreadScope() throws Exception { - Context context = Context.getCurrentContext(); - - ThreadScope thrScope = new ThreadScope(); - - thrScope.setPrototype(scope); - // We want 'thrScope' to be a new top-level scope, so set its - // parent scope to null. This means that any variables created - // by assignments will be properties of "thrScope". - thrScope.setParentScope(null); - // Put in the thread scope the Cocoon object, which gives access - // to the interpreter object, and some Cocoon objects. See - // FOM_Cocoon for more details. - Object[] args = {}; - FOM_Cocoon cocoon = (FOM_Cocoon) - context.newObject(thrScope, "FOM_Cocoon", args); - cocoon.setParentScope(thrScope); - thrScope.put("cocoon", thrScope, cocoon); - thrScope.defineProperty(LAST_EXEC_TIME, - new Long(0), - ScriptableObject.DONTENUM | ScriptableObject.PERMANENT); - - thrScope.reset(); - return thrScope; + return new ThreadScope(scope); } /** @@ -527,7 +537,7 @@ */ private void setupContext(Redirector redirector, Context context, ThreadScope thrScope) - throws Exception { + throws Exception { // Try to retrieve the scope object from the session instance. If // no scope is found, we create a new one, but don't place it in // the session. @@ -538,9 +548,9 @@ // behaviour allows multiple JavaScript functions to share the // same global scope. - FOM_Cocoon cocoon = (FOM_Cocoon)thrScope.get("cocoon", thrScope); - long lastExecTime = ((Long)thrScope.get(LAST_EXEC_TIME, - thrScope)).longValue(); + FOM_Cocoon cocoon = (FOM_Cocoon) thrScope.get("cocoon", thrScope); + long lastExecTime = ((Long) thrScope.get(LAST_EXEC_TIME, + thrScope)).longValue(); boolean needsRefresh = false; if (reloadScripts) { long now = System.currentTimeMillis(); @@ -549,6 +559,7 @@ } lastTimeCheck = now; } + // We need to setup the FOM_Cocoon object according to the current // request. Everything else remains the same. ClassLoader classLoader = getClassLoader(needsRefresh); @@ -589,16 +600,14 @@ } // Execute the scripts if necessary for (int i = 0, size = execList.size(); i < size; i++) { - String sourceURI = (String)execList.get(i); + String sourceURI = (String) execList.get(i); ScriptSourceEntry entry = - (ScriptSourceEntry)compiledScripts.get(sourceURI); + (ScriptSourceEntry) compiledScripts.get(sourceURI); long lastMod = entry.getSource().getLastModified(); Script script = entry.getScript(context, this.scope, false, this); if (lastExecTime == 0 || lastMod > lastExecTime) { script.exec(context, thrScope); - thrScope.put(LAST_EXEC_TIME, thrScope, - new Long(System.currentTimeMillis())); - thrScope.reset(); + thrScope.onExec(); } } } @@ -633,19 +642,15 @@ } protected Script compileScript(Context cx, Scriptable scope, Source src) - throws Exception { + throws Exception { InputStream is = src.getInputStream(); - if (is != null) { - try { - Reader reader = new BufferedReader(new InputStreamReader(is)); - Script compiledScript = cx.compileReader(scope, reader, - src.getURI(), 1, null); - return compiledScript; - } finally { - is.close(); - } - } else { - throw new ResourceNotFoundException(src.getURI() + ": not found"); + try { + Reader reader = new BufferedReader(new InputStreamReader(is)); + Script compiledScript = cx.compileReader(scope, reader, + src.getURI(), 1, null); + return compiledScript; + } finally { + is.close(); } } @@ -676,7 +681,7 @@ try { try { setupContext(redirector, context, thrScope); - cocoon = (FOM_Cocoon)thrScope.get("cocoon", thrScope); + cocoon = (FOM_Cocoon) thrScope.get("cocoon", thrScope); // Register the current scope for scripts indirectly called from this function FOM_JavaScriptFlowHelper.setFOM_FlowScope(cocoon.getObjectModel(), thrScope); @@ -689,11 +694,9 @@ } int size = (params != null ? params.size() : 0); - Object[] funArgs = new Object[size]; Scriptable parameters = context.newObject(thrScope); for (int i = 0; i < size; i++) { Interpreter.Argument arg = (Interpreter.Argument)params.get(i); - funArgs[i] = arg.value; if (arg.name == null) { arg.name = ""; } @@ -705,8 +708,9 @@ if (fun == Scriptable.NOT_FOUND) { throw new ResourceNotFoundException("Function \"javascript:" + funName + "()\" not found"); } + thrScope.setLock(true); - ScriptRuntime.call(context, fun, thrScope, funArgs, thrScope); + ScriptRuntime.call(context, fun, thrScope, new Object[0], thrScope); } catch (JavaScriptException ex) { EvaluatorException ee = Context.reportRuntimeError( ToolErrorReporter.getMessage("msg.uncaughtJSException", Modified: cocoon/trunk/status.xml ============================================================================== --- cocoon/trunk/status.xml (original) +++ cocoon/trunk/status.xml Thu Nov 11 18:28:23 2004 @@ -200,6 +200,10 @@ <changes> <release version="@version@" date="@date@"> + <action dev="VG" type="remove"> + Flowscript: Removed support for passing sitemap parameters into flowscript + function as positional arguments. Use cocoon.parameters instead. + </action> <action dev="RP" type="update" due-to="Igor Bukanov" fixes-bug="31649" due-to-email="[EMAIL PROTECTED]"> Use official Rhino implementation which supports continuations since 1.6. For the most flowscripts there shouldn't be any issues, though there are differences that may lead @@ -215,17 +219,13 @@ catch(return) and catch(continue) e.g. <code> var pool = ...; - function someFunction() { - var conn = pool.getConnection(); ... - catch (break) { conn.close(); conn = null; } - catch (continue) { conn = pool.getConnection(); } @@ -234,9 +234,7 @@ can be replaced by catching the ContinuationException: <code> var pool = ...; - function someFunction() { - var conn = null; try { if (conn == null) { @@ -370,6 +368,11 @@ </action> </release> <release version="2.1.6" date="TBD"> + <action dev="VG" type="remove"> + Flowscript: Deprecated support for passing sitemap parameters into flowscript + function as positional arguments. Use cocoon.parameters instead. Support will + be removed completely in Cocoon 2.2. + </action> <action dev="RG" type="fix" fixes-bug="32159" due-to="Michal Durdina" due-to-email="[EMAIL PROTECTED]"> Portal: Request content length and content type are required in portlet ActionRequest for custom upload handling.