diff --git a/config/alfresco/script-services-context.xml b/config/alfresco/script-services-context.xml index 2ed0a034c4..dad6620db4 100644 --- a/config/alfresco/script-services-context.xml +++ b/config/alfresco/script-services-context.xml @@ -18,7 +18,16 @@ js - + + + + true + + + + + true + diff --git a/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.java b/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.java index 9071cae12b..4a0244ec87 100644 --- a/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.java +++ b/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.java @@ -21,7 +21,6 @@ package org.alfresco.repo.jscript; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -89,6 +88,9 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess /** Flag to enable or disable runtime script compliation */ private boolean compile = true; + /** Flag to enable the sharing of sealed root scopes between scripts executions */ + private boolean shareSealedScopes = true; + /** Cache of runtime compiled script instances */ private final Map scriptCache = new ConcurrentHashMap(256); @@ -119,6 +121,15 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess this.compile = compile; } + /** + * @param shareSealedScopes true to allow sharing of sealed scopes between script executions - set to + * false to disable this feature and ensure that a new scope is created for each executed script. + */ + public void setShareSealedScopes(boolean shareSealedScopes) + { + this.shareSealedScopes = shareSealedScopes; + } + /** * @see org.alfresco.service.cmr.repository.ScriptProcessor#reset() */ @@ -414,10 +425,18 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess // Create a thread-specific scope from one of the shared scopes. // See http://www.mozilla.org/rhino/scopes.html cx.setWrapFactory(wrapFactory); - Scriptable sharedScope = secure ? this.nonSecureScope : this.secureScope; - Scriptable scope = cx.newObject(sharedScope); - scope.setPrototype(sharedScope); - scope.setParentScope(null); + Scriptable scope; + if (this.shareSealedScopes) + { + Scriptable sharedScope = secure ? this.nonSecureScope : this.secureScope; + scope = cx.newObject(sharedScope); + scope.setPrototype(sharedScope); + scope.setParentScope(null); + } + else + { + scope = initScope(cx, secure, false); + } // there's always a model, if only to hold the util objects if (model == null) @@ -531,7 +550,7 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess } } - + /** * Pre initializes two scope objects (one secure and one not) with the standard objects preinitialised. * This saves on very expensive calls to reinitialize a new scope on every web script execution. See @@ -541,38 +560,65 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess */ public void afterPropertiesSet() throws Exception { - // Initialise the secure scope + // Initialize the secure scope Context cx = Context.enter(); try { cx.setWrapFactory(wrapFactory); - this.secureScope = cx.initStandardObjects(null, true); - - // remove security issue related objects - this ensures the script may not access - // unsecure java.* libraries or import any other classes for direct access - only - // the configured root host objects will be available to the script writer - this.secureScope.delete("Packages"); - this.secureScope.delete("getClass"); - this.secureScope.delete("java"); + this.secureScope = initScope(cx, false, true); } finally { Context.exit(); } - // Initialise the non-secure scope + // Initialize the non-secure scope cx = Context.enter(); try { cx.setWrapFactory(wrapFactory); - - // allow access to all libraries and objects, including the importer - // @see http://www.mozilla.org/rhino/ScriptingJava.html - this.nonSecureScope = new ImporterTopLevel(cx, true); + this.nonSecureScope = initScope(cx, true, true); } finally { Context.exit(); } } + + /** + * Initializes a scope for script execution. The easiest way to embed Rhino is just to create a new scope this + * way whenever you need one. However, initStandardObjects() is an expensive method to call and it allocates a + * fair amount of memory. + * + * @param cx the thread execution context + * @param secure Do we consider the script secure? When false this ensures the script may not + * access insecure java.* libraries or import any other classes for direct access - only the + * configured root host objects will be available to the script writer. + * @param sealed Should the scope be sealed, making it immutable? This should be true if a scope + * is to be reused. + * @return the scope object + */ + protected Scriptable initScope(Context cx, boolean secure, boolean sealed) + { + Scriptable scope; + if (secure) + { + // Initialise the non-secure scope + // allow access to all libraries and objects, including the importer + // @see http://www.mozilla.org/rhino/ScriptingJava.html + scope = new ImporterTopLevel(cx, sealed); + } + else + { + // Initialise the secure scope + scope = cx.initStandardObjects(null, sealed); + // remove security issue related objects - this ensures the script may not access + // unsecure java.* libraries or import any other classes for direct access - only + // the configured root host objects will be available to the script writer + scope.delete("Packages"); + scope.delete("getClass"); + scope.delete("java"); + } + return scope; + } } \ No newline at end of file