Author: radu Date: Tue Jul 14 12:01:39 2015 New Revision: 1690905 URL: http://svn.apache.org/r1690905 Log: SLING-915 - [Rhino] Implement Compilable
* implemented Compilable support * added support for the ScripCache implemented in SLING-913 for scripts that are not executed as part of the normal Sling script resolution Modified: sling/trunk/bundles/scripting/javascript/pom.xml sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngine.java sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineFactory.java sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineTest.java sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/internal/ScriptEngineHelper.java Modified: sling/trunk/bundles/scripting/javascript/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/javascript/pom.xml?rev=1690905&r1=1690904&r2=1690905&view=diff ============================================================================== --- sling/trunk/bundles/scripting/javascript/pom.xml (original) +++ sling/trunk/bundles/scripting/javascript/pom.xml Tue Jul 14 12:01:39 2015 @@ -103,16 +103,25 @@ <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.api</artifactId> <version>2.1.0</version> + <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.scripting.api</artifactId> - <version>2.1.0</version> + <version>2.1.7-SNAPSHOT</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.scripting.core</artifactId> + <version>2.0.29-SNAPSHOT</version> + <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.jcr.resource</artifactId> <version>2.3.8</version> + <scope>provided</scope> <exclusions> <exclusion> <groupId>org.apache.jackrabbit</groupId> @@ -128,11 +137,13 @@ <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.commons.classloader</artifactId> <version>1.3.0</version> + <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.commons.json</artifactId> <version>2.0.6</version> + <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.sling</groupId> @@ -143,10 +154,12 @@ <dependency> <groupId>org.osgi</groupId> <artifactId>org.osgi.core</artifactId> + <scope>provided</scope> </dependency> <dependency> <groupId>org.osgi</groupId> <artifactId>org.osgi.compendium</artifactId> + <scope>provided</scope> </dependency> <dependency> <groupId>javax.jcr</groupId> @@ -157,10 +170,12 @@ <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> + <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.felix</groupId> <artifactId>org.apache.felix.scr.annotations</artifactId> + <scope>provided</scope> </dependency> <dependency> <groupId>org.mozilla</groupId> @@ -170,6 +185,7 @@ <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> + <scope>provided</scope> </dependency> <dependency> <groupId>commons-collections</groupId> @@ -177,6 +193,12 @@ <version>3.2.1</version> <scope>provided</scope> </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>1.4</version> + <scope>provided</scope> + </dependency> <!-- Testing --> <dependency> <groupId>org.apache.sling</groupId> @@ -184,5 +206,17 @@ <version>2.0.16</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-module-junit4</artifactId> + <version>1.6.2</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito</artifactId> + <version>1.6.2</version> + <scope>test</scope> + </dependency> </dependencies> </project> Modified: sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngine.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngine.java?rev=1690905&r1=1690904&r2=1690905&view=diff ============================================================================== --- sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngine.java (original) +++ sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngine.java Tue Jul 14 12:01:39 2015 @@ -16,25 +16,36 @@ */ package org.apache.sling.scripting.javascript.internal; +import java.io.IOException; +import java.io.InputStreamReader; import java.io.Reader; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import javax.script.Bindings; +import javax.script.Compilable; +import javax.script.CompiledScript; import javax.script.ScriptContext; +import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptException; +import org.apache.commons.io.IOUtils; import org.apache.sling.api.scripting.SlingBindings; import org.apache.sling.api.scripting.SlingScriptHelper; import org.apache.sling.commons.classloader.DynamicClassLoader; import org.apache.sling.scripting.api.AbstractSlingScriptEngine; +import org.apache.sling.scripting.api.CachedScript; +import org.apache.sling.scripting.api.ScriptCache; +import org.apache.sling.scripting.api.ScriptNameAware; +import org.apache.sling.scripting.core.ScriptNameAwareReader; import org.apache.sling.scripting.javascript.io.EspReader; import org.mozilla.javascript.ClassCache; import org.mozilla.javascript.Context; import org.mozilla.javascript.ImporterTopLevel; import org.mozilla.javascript.JavaScriptException; +import org.mozilla.javascript.Script; import org.mozilla.javascript.ScriptRuntime; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; @@ -48,152 +59,102 @@ import org.slf4j.LoggerFactory; * A ScriptEngine that uses the Rhino interpreter to process Sling requests with * server-side javascript. */ -public class RhinoJavaScriptEngine extends AbstractSlingScriptEngine { +public class RhinoJavaScriptEngine extends AbstractSlingScriptEngine implements Compilable { private static final Logger LOGGER = LoggerFactory.getLogger(RhinoJavaScriptEngine.class); + private static final String NO_SCRIPT_NAME = "NO_SCRIPT_NAME"; private Scriptable rootScope; + private ScriptCache scriptCache; - public RhinoJavaScriptEngine(ScriptEngineFactory factory, - Scriptable rootScope) { + public RhinoJavaScriptEngine(ScriptEngineFactory factory, Scriptable rootScope, ScriptCache scriptCache) { super(factory); this.rootScope = rootScope; + this.scriptCache = scriptCache; } - public Object eval(Reader scriptReader, ScriptContext scriptContext) - throws ScriptException { - Bindings bindings = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE); - String scriptName = "NO_SCRIPT_NAME"; - { - SlingScriptHelper helper = (SlingScriptHelper) bindings.get(SlingBindings.SLING); - if (helper != null) { - scriptName = helper.getScript().getScriptResource().getPath(); - } - } - - // wrap the reader in an EspReader for ESP scripts - if (scriptName.endsWith(RhinoJavaScriptEngineFactory.ESP_SCRIPT_EXTENSION)) { - scriptReader = new EspReader(scriptReader); - } - - // container for replaced properties - Map<String, Object> replacedProperties = null; - Scriptable scope = null; - boolean isTopLevelCall = false; - - // create a rhino Context and execute the script + public CompiledScript compile(String script) throws ScriptException { + Reader reader = null; try { + reader = new InputStreamReader(IOUtils.toInputStream(script)); + return compile(reader); + } finally { + IOUtils.closeQuietly(reader); + } + } - final Context rhinoContext = Context.enter(); - rhinoContext.setOptimizationLevel(optimizationLevel()); - - if (ScriptRuntime.hasTopCall(rhinoContext)) { - // reuse the top scope if we are included - scope = ScriptRuntime.getTopCallScope(rhinoContext); - - } else { - // create the request top scope, use the ImporterToplevel here - // to support the importPackage and importClasses functions - scope = new ImporterTopLevel(); - - // Set the global scope to be our prototype - scope.setPrototype(rootScope); - - // We want "scope" 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 "scope". - scope.setParentScope(null); - - // setup the context for use - WrapFactory wrapFactory = ((RhinoJavaScriptEngineFactory) getFactory()).getWrapFactory(); - rhinoContext.setWrapFactory(wrapFactory); - - // this is the top level call - isTopLevelCall = true; - } - - // add initial properties to the scope - replacedProperties = setBoundProperties(scope, bindings); - - final int lineNumber = 1; - final Object securityDomain = null; - - Object result = rhinoContext.evaluateReader(scope, scriptReader, scriptName, - lineNumber, securityDomain); - - if (result instanceof Wrapper) { - result = ((Wrapper) result).unwrap(); - } - - return (result instanceof Undefined) ? null : result; - - } catch (JavaScriptException t) { - - // prevent variables to be pushed back in case of errors - isTopLevelCall = false; - - final ScriptException se = new ScriptException(t.details(), - t.sourceName(), t.lineNumber()); - - // log the script stack trace - ((Logger) bindings.get(SlingBindings.LOG)).error(t.getScriptStackTrace()); - - // set the exception cause - Object value = t.getValue(); - if (value != null) { - if (value instanceof Wrapper) { - value = ((Wrapper) value).unwrap(); - } - if (value instanceof Throwable) { - se.initCause((Throwable) value); + public CompiledScript compile(Reader scriptReader) throws ScriptException { + final String scriptName = getScriptName(scriptReader); + CachedScript cachedScript = scriptCache.getScript(scriptName); + if (cachedScript != null) { + LOGGER.debug("Detected cached script for {}.", scriptName); + return cachedScript.getCompiledScript(); + } else { + scriptReader = wrapReaderIfEspScript(scriptReader, scriptName); + try { + final Context rhinoContext = Context.enter(); + rhinoContext.setOptimizationLevel(optimizationLevel()); + + if (!ScriptRuntime.hasTopCall(rhinoContext)) { + // setup the context for use + WrapFactory wrapFactory = ((RhinoJavaScriptEngineFactory) getFactory()).getWrapFactory(); + rhinoContext.setWrapFactory(wrapFactory); } - } - - // if the cause could not be set, overwrite the stack trace - if (se.getCause() == null) { - se.setStackTrace(t.getStackTrace()); - } - - throw se; - } catch (Throwable t) { + final int lineNumber = 1; + final Object securityDomain = null; - // prevent variables to be pushed back in case of errors - isTopLevelCall = false; - - final ScriptException se = new ScriptException( - "Failure running script " + scriptName + ": " + t.getMessage()); - se.initCause(t); - throw se; + final Script script = rhinoContext.compileReader(scriptReader, scriptName, lineNumber, securityDomain); + final SlingCompiledScript slingCompiledScript = new SlingCompiledScript(script, this); + cachedScript = new CachedScript() { + @Override + public String getScriptPath() { + return scriptName; + } - } finally { + @Override + public CompiledScript getCompiledScript() { + return slingCompiledScript; + } + }; + scriptCache.putScript(cachedScript); + LOGGER.debug("Added {} script to Script Cache.", scriptName); + return slingCompiledScript; + } catch (IOException e) { + final ScriptException se = new ScriptException("Failure running script " + scriptName + ": " + e.getMessage()); + se.initCause(e); + throw se; + } finally { + Context.exit(); + } + } + } - // if we are the top call (the Context is now null) we have to - // play back any properties from the scope back to the bindings - if (isTopLevelCall) { - getBoundProperties(scope, bindings); - } - - // if properties have been replaced, reset them - resetBoundProperties(scope, replacedProperties); - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - if (classLoader instanceof DynamicClassLoader) { - DynamicClassLoader dynamicClassLoader = (DynamicClassLoader) classLoader; - if (!dynamicClassLoader.isLive()) { - /** - * if the classloader on this thread is a dynamic class loader and it's dirty we should clear Rhino's class cache - * to avoid classloader leaks - */ - if (scope != null) { - ClassCache classCache = ClassCache.get(scope); - classCache.clearCaches(); - LOGGER.info("Detected dirty classloader on thread {}. Emptying Rhino's class cache.", Thread.currentThread() - .getName()); + public Object eval(Reader scriptReader, ScriptContext scriptContext) throws ScriptException { + String scriptName = getScriptName(scriptReader); + Reader reader = wrapReaderIfEspScript(scriptReader, scriptName); + if (!(scriptReader instanceof ScriptNameAware)) { + if (NO_SCRIPT_NAME.equals(scriptName)) { + String script = (String) scriptContext.getBindings(ScriptContext.ENGINE_SCOPE).get(ScriptEngine.FILENAME); + if (script != null) { + for (String extension : getFactory().getExtensions()) { + if (script.endsWith(extension)) { + scriptName = script; + reader = new ScriptNameAwareReader(reader, scriptName); + break; + } } } } - Context.exit(); } + return compile(reader).eval(scriptContext); + } + + private Reader wrapReaderIfEspScript(Reader scriptReader, String scriptName) { + if (scriptName.endsWith(RhinoJavaScriptEngineFactory.ESP_SCRIPT_EXTENSION)) { + scriptReader = new EspReader(scriptReader); + } + return scriptReader; } private Map<String, Object> setBoundProperties(Scriptable scope, @@ -251,4 +212,154 @@ public class RhinoJavaScriptEngine exten private int optimizationLevel() { return ((RhinoJavaScriptEngineFactory)getFactory()).getOptimizationLevel(); } + + private class SlingCompiledScript extends CompiledScript { + + private final Script script; + private final ScriptEngine engine; + + SlingCompiledScript(Script script, ScriptEngine engine) { + this.script = script; + this.engine = engine; + } + + @Override + public Object eval(ScriptContext scriptContext) throws ScriptException { + Bindings bindings = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE); + String scriptName = "NO_SCRIPT_NAME"; + { + SlingScriptHelper helper = (SlingScriptHelper) bindings.get(SlingBindings.SLING); + if (helper != null) { + scriptName = helper.getScript().getScriptResource().getPath(); + } + } + + // container for replaced properties + Map<String, Object> replacedProperties = null; + Scriptable scope = null; + boolean isTopLevelCall = false; + + // create a rhino Context and execute the script + try { + + final Context rhinoContext = Context.enter(); + rhinoContext.setOptimizationLevel(optimizationLevel()); + + if (ScriptRuntime.hasTopCall(rhinoContext)) { + // reuse the top scope if we are included + scope = ScriptRuntime.getTopCallScope(rhinoContext); + + } else { + // create the request top scope, use the ImporterToplevel here + // to support the importPackage and importClasses functions + scope = new ImporterTopLevel(); + + // Set the global scope to be our prototype + scope.setPrototype(rootScope); + + // We want "scope" 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 "scope". + scope.setParentScope(null); + + // setup the context for use + WrapFactory wrapFactory = ((RhinoJavaScriptEngineFactory) getFactory()).getWrapFactory(); + rhinoContext.setWrapFactory(wrapFactory); + + // this is the top level call + isTopLevelCall = true; + } + + // add initial properties to the scope + replacedProperties = setBoundProperties(scope, bindings); + + Object result = script.exec(rhinoContext, scope); + + if (result instanceof Wrapper) { + result = ((Wrapper) result).unwrap(); + } + + return (result instanceof Undefined) ? null : result; + + } catch (JavaScriptException t) { + + // prevent variables to be pushed back in case of errors + isTopLevelCall = false; + + final ScriptException se = new ScriptException(t.details(), + t.sourceName(), t.lineNumber()); + + // log the script stack trace + ((Logger) bindings.get(SlingBindings.LOG)).error(t.getScriptStackTrace()); + + // set the exception cause + Object value = t.getValue(); + if (value != null) { + if (value instanceof Wrapper) { + value = ((Wrapper) value).unwrap(); + } + if (value instanceof Throwable) { + se.initCause((Throwable) value); + } + } + + // if the cause could not be set, overwrite the stack trace + if (se.getCause() == null) { + se.setStackTrace(t.getStackTrace()); + } + + throw se; + + } catch (Throwable t) { + + // prevent variables to be pushed back in case of errors + isTopLevelCall = false; + + final ScriptException se = new ScriptException( + "Failure running script " + scriptName + ": " + t.getMessage()); + se.initCause(t); + throw se; + + } finally { + + // if we are the top call (the Context is now null) we have to + // play back any properties from the scope back to the bindings + if (isTopLevelCall) { + getBoundProperties(scope, bindings); + } + + // if properties have been replaced, reset them + resetBoundProperties(scope, replacedProperties); + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + if (classLoader instanceof DynamicClassLoader) { + DynamicClassLoader dynamicClassLoader = (DynamicClassLoader) classLoader; + if (!dynamicClassLoader.isLive()) { + /** + * if the class loader on this thread is a dynamic class loader and it's dirty we should clear Rhino's class cache + * to avoid class loader leaks + */ + if (scope != null) { + ClassCache classCache = ClassCache.get(scope); + classCache.clearCaches(); + LOGGER.info("Detected dirty class loader on thread {}. Emptying Rhino's class cache.", Thread.currentThread() + .getName()); + } + } + } + Context.exit(); + } + } + + @Override + public ScriptEngine getEngine() { + return engine; + } + } + + private String getScriptName(Reader scriptReader) { + if(scriptReader instanceof ScriptNameAware){ + return ((ScriptNameAware) scriptReader).getScriptName(); + } + return NO_SCRIPT_NAME; + } } Modified: sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineFactory.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineFactory.java?rev=1690905&r1=1690904&r2=1690905&view=diff ============================================================================== --- sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineFactory.java (original) +++ sling/trunk/bundles/scripting/javascript/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineFactory.java Tue Jul 14 12:01:39 2015 @@ -22,6 +22,7 @@ import java.util.Dictionary; import java.util.HashSet; import java.util.Set; import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; @@ -34,6 +35,7 @@ import org.apache.felix.scr.annotations. import org.apache.sling.commons.classloader.DynamicClassLoaderManager; import org.apache.sling.commons.osgi.PropertiesUtil; import org.apache.sling.scripting.api.AbstractScriptEngineFactory; +import org.apache.sling.scripting.api.ScriptCache; import org.apache.sling.scripting.javascript.RhinoHostObjectProvider; import org.apache.sling.scripting.javascript.SlingWrapper; import org.apache.sling.scripting.javascript.helper.SlingContextFactory; @@ -61,39 +63,48 @@ import org.slf4j.LoggerFactory; /** * The <code>RhinoJavaScriptEngineFactory</code> TODO - * */ @Component( metatype = true, - label="Apache Sling Rhino Javascript Engine Factory", - description="Javascript engine based on Rino") -@Service(value=javax.script.ScriptEngineFactory.class) -@Reference(name="HostObjectProvider", referenceInterface=RhinoHostObjectProvider.class, - cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE, policy=ReferencePolicy.DYNAMIC, - bind="addHostObjectProvider", unbind="removeHostObjectProvider") + label = "Apache Sling Rhino Javascript Engine Factory", + description = "Javascript engine based on Rhino" +) +@Service(ScriptEngineFactory.class) +@Reference( + name = "HostObjectProvider", + referenceInterface = RhinoHostObjectProvider.class, + cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, + policy = ReferencePolicy.DYNAMIC, + bind = "addHostObjectProvider", + unbind = "removeHostObjectProvider" +) @Property( name = RhinoJavaScriptEngineFactory.OPTIMIZATION_CONFIG, label = "Rhino optimization level", intValue = RhinoJavaScriptEngineFactory.DEFAULT_OPTIMIZATION_LEVEL, - description = "The level of optimization for the bytecode generated by Rhino. Provide values between 0-9, 9 being the most aggressive level of optimization. A value of -1 will run scripts in interpreted mode") -public class RhinoJavaScriptEngineFactory extends AbstractScriptEngineFactory - implements ScopeProvider { + description = "The level of optimization for the bytecode generated by Rhino. Provide values between 0-9, 9 being the most " + + "aggressive level of optimization. A value of -1 will run scripts in interpreted mode." +) +public class RhinoJavaScriptEngineFactory extends AbstractScriptEngineFactory implements ScopeProvider { public final static String OPTIMIZATION_CONFIG = "org.apache.sling.scripting.javascript.rhino.optLevel"; - public final static int DEFAULT_OPTIMIZATION_LEVEL = - 1; + public final static int DEFAULT_OPTIMIZATION_LEVEL = 9; public final static String ECMA_SCRIPT_EXTENSION = "ecma"; public final static String ESP_SCRIPT_EXTENSION = "esp"; private static final Class<?>[] HOSTOBJECT_CLASSES = { - ScriptableResource.class, ScriptableNode.class, - ScriptableProperty.class, ScriptableItemMap.class, - ScriptablePrintWriter.class, ScriptableVersionHistory.class, - ScriptableVersion.class, ScriptableCalendar.class }; + ScriptableResource.class, ScriptableNode.class, + ScriptableProperty.class, ScriptableItemMap.class, + ScriptablePrintWriter.class, ScriptableVersionHistory.class, + ScriptableVersion.class, ScriptableCalendar.class + }; - /** default log */ + /** + * default log + */ private final Logger log = LoggerFactory.getLogger(getClass()); private int optimizationLevel; @@ -107,10 +118,13 @@ public class RhinoJavaScriptEngineFactor private final Set<RhinoHostObjectProvider> hostObjectProvider = new HashSet<RhinoHostObjectProvider>(); @Reference - private DynamicClassLoaderManager dynamicClassLoaderManager; + private DynamicClassLoaderManager dynamicClassLoaderManager = null; + + @Reference + private ScriptCache scriptCache = null; public ScriptEngine getScriptEngine() { - return new RhinoJavaScriptEngine(this, getRootScope()); + return new RhinoJavaScriptEngine(this, getRootScope(), scriptCache); } public String getLanguageName() { @@ -124,6 +138,7 @@ public class RhinoJavaScriptEngineFactor /** * Get the optimization level that should be used when running JS scripts * with Rhino + * * @return an integer from 0-9 with 9 being the most aggressive optimization, or * -1 if interpreted mode is to be used */ @@ -154,20 +169,16 @@ public class RhinoJavaScriptEngineFactor final Context rhinoContext = Context.enter(); try { - Scriptable tmpScope = rhinoContext.initStandardObjects( - new ImporterTopLevel(), false); + Scriptable tmpScope = rhinoContext.initStandardObjects(new ImporterTopLevel(), false); // default classes - addHostObjects(tmpScope, - (Class<? extends ScriptableObject>[]) HOSTOBJECT_CLASSES); + addHostObjects(tmpScope, (Class<? extends ScriptableObject>[]) HOSTOBJECT_CLASSES); // provided classes for (RhinoHostObjectProvider provider : hostObjectProvider) { addHostObjects(tmpScope, provider.getHostObjectClasses()); - addImportedClasses(rhinoContext, tmpScope, - provider.getImportedClasses()); - addImportedPackages(rhinoContext, tmpScope, - provider.getImportedPackages()); + addImportedClasses(rhinoContext, tmpScope, provider.getImportedClasses()); + addImportedPackages(rhinoContext, tmpScope, provider.getImportedPackages()); } // only assign the root scope when complete set up @@ -201,9 +212,7 @@ public class RhinoJavaScriptEngineFactor @Activate protected void activate(ComponentContext context) { Dictionary<?, ?> props = context.getProperties(); - boolean debugging = getProperty( - "org.apache.sling.scripting.javascript.debug", props, - context.getBundleContext(), false); + boolean debugging = getProperty("org.apache.sling.scripting.javascript.debug", props, context.getBundleContext(), false); optimizationLevel = readOptimizationLevel(props); @@ -214,14 +223,12 @@ public class RhinoJavaScriptEngineFactor SlingContextFactory.setup(this); Context cx = Context.enter(); - setEngineName(getEngineName() + " (" + cx.getImplementationVersion() - + ")"); + setEngineName(getEngineName() + " (" + cx.getImplementationVersion() + ")"); languageVersion = String.valueOf(cx.getLanguageVersion()); Context.exit(); setExtensions(ECMA_SCRIPT_EXTENSION, ESP_SCRIPT_EXTENSION); - setMimeTypes("text/javascript", "application/ecmascript", - "application/javascript"); + setMimeTypes("text/javascript", "application/ecmascript", "application/javascript"); setNames("javascript", ECMA_SCRIPT_EXTENSION, ESP_SCRIPT_EXTENSION); final ContextFactory contextFactory = ContextFactory.getGlobal(); @@ -230,14 +237,15 @@ public class RhinoJavaScriptEngineFactor } // set the dynamic class loader as the application class loader final DynamicClassLoaderManager dclm = this.dynamicClassLoaderManager; - if ( dclm != null ) { + if (dclm != null) { contextFactory.initApplicationClassLoader(dynamicClassLoaderManager.getDynamicClassLoader()); } - + log.info("Activated with optimization level {}", optimizationLevel); } @Deactivate + @SuppressWarnings("unused") protected void deactivate(ComponentContext context) { // remove the root scope @@ -251,6 +259,7 @@ public class RhinoJavaScriptEngineFactor hostObjectProvider.clear(); } + @SuppressWarnings("unused") protected void addHostObjectProvider(RhinoHostObjectProvider provider) { hostObjectProvider.add(provider); @@ -259,6 +268,7 @@ public class RhinoJavaScriptEngineFactor } } + @SuppressWarnings("unused") protected void removeHostObjectProvider(RhinoHostObjectProvider provider) { // remove the current root scope and have it recreated using the // new host object classes @@ -269,8 +279,7 @@ public class RhinoJavaScriptEngineFactor // ---------- internal - private void addHostObjects(Scriptable scope, - Class<? extends Scriptable>[] classes) { + private void addHostObjects(Scriptable scope, Class<? extends Scriptable>[] classes) { if (classes != null) { for (Class<? extends Scriptable> clazz : classes) { try { @@ -283,30 +292,23 @@ public class RhinoJavaScriptEngineFactor // SlingWrappers can map to several classes if needed final SlingWrapper hostWrapper = (SlingWrapper) clazz.newInstance(); for (Class<?> c : hostWrapper.getWrappedClasses()) { - getWrapFactory().registerWrapper(c, - hostWrapper.getClassName()); + getWrapFactory().registerWrapper(c, hostWrapper.getClassName()); } - } else { - // but other Scriptable host objects need to be // registered as well final Scriptable host = clazz.newInstance(); - getWrapFactory().registerWrapper( - host.getClass(), host.getClassName()); - + getWrapFactory().registerWrapper(host.getClass(), host.getClassName()); } - } catch (Throwable t) { - log.warn("addHostObjects: Cannot prepare host object " - + clazz, t); + log.warn("addHostObjects: Cannot prepare host object " + clazz, t); } } } } private void addImportedClasses(Context cx, Scriptable scope, - Class<?>[] classes) { + Class<?>[] classes) { if (classes != null && classes.length > 0) { NativeJavaClass[] np = new NativeJavaClass[classes.length]; for (int i = 0; i < classes.length; i++) { @@ -317,7 +319,7 @@ public class RhinoJavaScriptEngineFactor } private void addImportedPackages(Context cx, Scriptable scope, - String[] packages) { + String[] packages) { if (packages != null && packages.length > 0) { NativeJavaPackage[] np = new NativeJavaPackage[packages.length]; for (int i = 0; i < packages.length; i++) { @@ -328,7 +330,7 @@ public class RhinoJavaScriptEngineFactor } private boolean getProperty(String name, Dictionary<?, ?> props, - BundleContext bundleContext, boolean defaultValue) { + BundleContext bundleContext, boolean defaultValue) { Object value = props.get(name); if (value == null) { value = bundleContext.getProperty(name); Modified: sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineTest.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineTest.java?rev=1690905&r1=1690904&r2=1690905&view=diff ============================================================================== --- sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineTest.java (original) +++ sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngineTest.java Tue Jul 14 12:01:39 2015 @@ -23,15 +23,19 @@ import javax.script.ScriptEngine; import javax.script.ScriptException; import javax.script.SimpleBindings; -import junit.framework.TestCase; - +import org.apache.sling.scripting.api.ScriptCache; import org.apache.sling.scripting.javascript.helper.SlingWrapFactory; +import org.mockito.Mockito; import org.mozilla.javascript.Context; import org.mozilla.javascript.ImporterTopLevel; import org.mozilla.javascript.Scriptable; +import junit.framework.TestCase; + public class RhinoJavaScriptEngineTest extends TestCase { + private static ScriptCache scriptCache = Mockito.mock(ScriptCache.class); + public void testPreserveScopeBetweenEvals() throws ScriptException { MockRhinoJavaScriptEngineFactory factory = new MockRhinoJavaScriptEngineFactory(); ScriptEngine engine = factory.getScriptEngine(); @@ -55,7 +59,7 @@ public class RhinoJavaScriptEngineTest e public ScriptEngine getScriptEngine() { final Context rhinoContext = Context.enter(); Scriptable scope = rhinoContext.initStandardObjects(new ImporterTopLevel(), false); - return new RhinoJavaScriptEngine(this, scope); + return new RhinoJavaScriptEngine(this, scope, scriptCache); } @Override Modified: sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/internal/ScriptEngineHelper.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/internal/ScriptEngineHelper.java?rev=1690905&r1=1690904&r2=1690905&view=diff ============================================================================== --- sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/internal/ScriptEngineHelper.java (original) +++ sling/trunk/bundles/scripting/javascript/src/test/java/org/apache/sling/scripting/javascript/internal/ScriptEngineHelper.java Tue Jul 14 12:01:39 2015 @@ -18,15 +18,11 @@ */ package org.apache.sling.scripting.javascript.internal; -import java.io.File; -import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StringWriter; -import java.util.Dictionary; import java.util.HashMap; import java.util.Map; - import javax.script.Bindings; import javax.script.ScriptContext; import javax.script.ScriptEngine; @@ -36,24 +32,19 @@ import javax.script.SimpleScriptContext; import org.apache.sling.commons.testing.osgi.MockBundle; import org.apache.sling.commons.testing.osgi.MockComponentContext; +import org.apache.sling.scripting.api.ScriptCache; +import org.mockito.Mockito; +import org.mockito.internal.util.reflection.Whitebox; import org.mozilla.javascript.Context; import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.Wrapper; -import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleException; -import org.osgi.framework.BundleListener; -import org.osgi.framework.Filter; -import org.osgi.framework.FrameworkListener; -import org.osgi.framework.InvalidSyntaxException; -import org.osgi.framework.ServiceListener; -import org.osgi.framework.ServiceReference; -import org.osgi.framework.ServiceRegistration; /** Helpers to run javascript code fragments in tests */ public class ScriptEngineHelper { private static ScriptEngine engine; + private static ScriptCache scriptCache = Mockito.mock(ScriptCache.class); public static class Data extends HashMap<String, Object> { } @@ -62,6 +53,7 @@ public class ScriptEngineHelper { if (engine == null) { synchronized (ScriptEngineHelper.class) { RhinoJavaScriptEngineFactory f = new RhinoJavaScriptEngineFactory(); + Whitebox.setInternalState(f, "scriptCache", scriptCache); f.activate(new RhinoMockComponentContext()); engine = f.getScriptEngine(); } @@ -121,139 +113,15 @@ public class ScriptEngineHelper { private static class RhinoMockComponentContext extends MockComponentContext { + private BundleContext bundleContext = Mockito.mock(BundleContext.class); + private RhinoMockComponentContext() { super(new MockBundle(0)); } @Override public BundleContext getBundleContext() { - return new BundleContext() { - - public void addBundleListener(BundleListener arg0) { - // TODO Auto-generated method stub - - } - - public void addFrameworkListener( - FrameworkListener arg0) { - // TODO Auto-generated method stub - - } - - public void addServiceListener(ServiceListener arg0) { - // TODO Auto-generated method stub - - } - - public void addServiceListener( - ServiceListener arg0, String arg1) - throws InvalidSyntaxException { - // TODO Auto-generated method stub - - } - - public Filter createFilter(String arg0) - throws InvalidSyntaxException { - // TODO Auto-generated method stub - return null; - } - - public ServiceReference[] getAllServiceReferences( - String arg0, String arg1) - throws InvalidSyntaxException { - // TODO Auto-generated method stub - return null; - } - - public Bundle getBundle() { - // TODO Auto-generated method stub - return null; - } - - public Bundle getBundle(long arg0) { - // TODO Auto-generated method stub - return null; - } - - public Bundle[] getBundles() { - // TODO Auto-generated method stub - return null; - } - - public File getDataFile(String arg0) { - // TODO Auto-generated method stub - return null; - } - - public String getProperty(String arg0) { - // TODO Auto-generated method stub - return null; - } - - public Object getService(ServiceReference arg0) { - // TODO Auto-generated method stub - return null; - } - - public ServiceReference getServiceReference( - String arg0) { - // TODO Auto-generated method stub - return null; - } - - public ServiceReference[] getServiceReferences( - String arg0, String arg1) - throws InvalidSyntaxException { - // TODO Auto-generated method stub - return null; - } - - public Bundle installBundle(String arg0) - throws BundleException { - // TODO Auto-generated method stub - return null; - } - - public Bundle installBundle(String arg0, - InputStream arg1) throws BundleException { - // TODO Auto-generated method stub - return null; - } - - public ServiceRegistration registerService( - String[] arg0, Object arg1, Dictionary arg2) { - // TODO Auto-generated method stub - return null; - } - - public ServiceRegistration registerService( - String arg0, Object arg1, Dictionary arg2) { - // TODO Auto-generated method stub - return null; - } - - public void removeBundleListener(BundleListener arg0) { - // TODO Auto-generated method stub - - } - - public void removeFrameworkListener( - FrameworkListener arg0) { - // TODO Auto-generated method stub - - } - - public void removeServiceListener( - ServiceListener arg0) { - // TODO Auto-generated method stub - - } - - public boolean ungetService(ServiceReference arg0) { - // TODO Auto-generated method stub - return false; - } - }; + return bundleContext; } } }