This is an automated email from the ASF dual-hosted git repository. radu pushed a commit to branch issue/SLING-7134 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-core.git
commit 2e15bd4f230d390ceadc9481627156bb3b6caaa3 Author: Radu Cotescu <[email protected]> AuthorDate: Sun Dec 3 13:23:55 2017 +0100 SLING-7134 - Script execution order is not deterministic on Java 9 * reimplemented the former o.a.s.scripting.core.impl.ScriptEngineManagerFactory, o.a.s.scripting.core.impl.helper.SlingScriptEngineManager and o.a.s.scripting.core.impl.helper.ProxyScriptEngineManager into one service: o.a.s.scripting.core.impl.jsr223.SlingScriptEngineManager * the new SlingScriptEngineManager manages ScriptEngineFactories registrations from the platform's ScriptEngineManager, bundles that expose a ScriptEngineFactory through the SPI mechanism and ScriptEngineFactories registered as OSGi services * introduced the concept of a SortableScriptEngineFactory, that allows ordering the factories based on bundle IDs and service rankings; if two factories have the same service ranking, then the factory with the higher bundle ID will win * corrected bug in the ScriptCacheImpl to cache scripts from all ScriptEngineFactories that register a Compilable ScriptEngine, not just for the ScriptEngineFactories registered as OSGi services * extended tests * updated PAX exam tests to run on Java 9 --- pom.xml | 21 +- .../impl/BindingsValuesProvidersByContextImpl.java | 4 +- .../sling/scripting/core/impl/ScriptCacheImpl.java | 52 ++-- .../core/impl/ScriptEngineConsolePlugin.java | 109 +++---- .../core/impl/ScriptEngineManagerFactory.java | 281 ------------------ .../core/impl/SlingScriptAdapterFactory.java | 2 +- .../core/impl/helper/ProxyScriptEngineManager.java | 107 ------- .../core/impl/helper/SlingScriptEngineManager.java | 77 ----- .../core/impl/jsr223/SlingScriptEngineManager.java | 320 +++++++++++++++++++++ .../impl/jsr223/SortableScriptEngineFactory.java | 134 +++++++++ .../sling/scripting/core/ScriptHelperTest.java | 6 +- .../core/impl/ScriptEngineManagerFactoryTest.java | 168 ----------- .../{ => jsr223}/DummyScriptEngineFactory.java | 36 +-- .../impl/jsr223/SlingScriptEngineManagerTest.java | 208 ++++++++++++++ .../jsr223/SortableScriptEngineFactoryTest.java | 174 +++++++++++ .../core/it/ScriptingCoreTestSupport.java | 16 +- 16 files changed, 957 insertions(+), 758 deletions(-) diff --git a/pom.xml b/pom.xml index a49404b..9166e97 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ <parent> <groupId>org.apache.sling</groupId> <artifactId>sling</artifactId> - <version>30</version> + <version>32</version> <relativePath /> </parent> @@ -37,7 +37,7 @@ </description> <properties> - <org.ops4j.pax.exam.version>4.10.0</org.ops4j.pax.exam.version> + <org.ops4j.pax.exam.version>4.11.0</org.ops4j.pax.exam.version> </properties> <scm> @@ -140,7 +140,7 @@ <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.commons.osgi</artifactId> - <version>2.1.0</version> + <version>2.4.0</version> <scope>provided</scope> </dependency> <dependency> @@ -182,7 +182,7 @@ <dependency> <groupId>org.apache.felix</groupId> <artifactId>org.apache.felix.webconsole</artifactId> - <version>3.1.8</version> + <version>4.2.0</version> <scope>provided</scope> </dependency> <dependency> @@ -221,23 +221,28 @@ <dependency> <groupId>org.apache.felix</groupId> <artifactId>org.apache.felix.framework</artifactId> - <version>5.6.2</version> + <version>5.6.10</version> <scope>test</scope> </dependency> - <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.testing.osgi-mock</artifactId> - <version>2.0.2</version> + <version>2.3.5-SNAPSHOT</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.testing.sling-mock</artifactId> - <version>1.6.0</version> + <version>2.2.14</version> <scope>test</scope> + <exclusions> + <exclusion> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.scripting.core</artifactId> + </exclusion> + </exclusions> </dependency> <dependency> diff --git a/src/main/java/org/apache/sling/scripting/core/impl/BindingsValuesProvidersByContextImpl.java b/src/main/java/org/apache/sling/scripting/core/impl/BindingsValuesProvidersByContextImpl.java index b8fdec5..63f439c 100644 --- a/src/main/java/org/apache/sling/scripting/core/impl/BindingsValuesProvidersByContextImpl.java +++ b/src/main/java/org/apache/sling/scripting/core/impl/BindingsValuesProvidersByContextImpl.java @@ -34,7 +34,7 @@ import javax.script.ScriptEngineFactory; import org.apache.sling.commons.osgi.PropertiesUtil; import org.apache.sling.scripting.api.BindingsValuesProvider; import org.apache.sling.scripting.api.BindingsValuesProvidersByContext; -import org.apache.sling.scripting.core.impl.helper.SlingScriptEngineManager; +import org.apache.sling.scripting.core.impl.jsr223.SlingScriptEngineManager; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; @@ -151,7 +151,7 @@ public class BindingsValuesProvidersByContextImpl implements BindingsValuesProvi // we load the compatible language ones first so that the most specific // overrides these - Map<Object, Object> factoryProps = scriptEngineManager.getProperties(scriptEngineFactory); + Map<String, Object> factoryProps = scriptEngineManager.getProperties(scriptEngineFactory); if (factoryProps != null) { String[] compatibleLangs = PropertiesUtil.toStringArray(factoryProps.get("compatible.javax.script.name"), new String[0]); for (final String name : compatibleLangs) { diff --git a/src/main/java/org/apache/sling/scripting/core/impl/ScriptCacheImpl.java b/src/main/java/org/apache/sling/scripting/core/impl/ScriptCacheImpl.java index 013e758..a17e05d 100644 --- a/src/main/java/org/apache/sling/scripting/core/impl/ScriptCacheImpl.java +++ b/src/main/java/org/apache/sling/scripting/core/impl/ScriptCacheImpl.java @@ -47,6 +47,7 @@ import org.apache.sling.commons.threads.ThreadPoolManager; import org.apache.sling.scripting.api.CachedScript; import org.apache.sling.scripting.api.ScriptCache; import org.apache.sling.scripting.core.impl.helper.CachingMap; +import org.apache.sling.scripting.core.impl.jsr223.SlingScriptEngineManager; import org.apache.sling.serviceusermapping.ServiceUserMapped; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; @@ -57,22 +58,18 @@ import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventConstants; +import org.osgi.service.event.EventHandler; import org.osgi.service.metatype.annotations.Designate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Component( - service = ScriptCache.class, - reference = @Reference( - name = "ScriptEngineFactory", - bind = "bindScriptEngineFactory", - unbind = "unbindScriptEngineFactory", - service = ScriptEngineFactory.class, - cardinality = ReferenceCardinality.MULTIPLE, - policy = ReferencePolicy.DYNAMIC - ), + service = {ScriptCache.class, EventHandler.class}, property = { - Constants.SERVICE_VENDOR + "=The Apache Software Foundation" + Constants.SERVICE_VENDOR + "=The Apache Software Foundation", + EventConstants.EVENT_TOPIC + "=org/apache/sling/scripting/core/impl/jsr223/SlingScriptEngineManager/*" } ) @Designate( @@ -82,7 +79,7 @@ import org.slf4j.LoggerFactory; * The {@code ScriptCache} stores information about {@link CompiledScript} instances evaluated by various {@link ScriptEngine}s that * implement the {@link Compilable} interface. */ -public class ScriptCacheImpl implements ScriptCache, ResourceChangeListener, ExternalResourceChangeListener { +public class ScriptCacheImpl implements ScriptCache, ResourceChangeListener, ExternalResourceChangeListener, EventHandler { private final Logger LOGGER = LoggerFactory.getLogger(ScriptCacheImpl.class); @@ -102,6 +99,9 @@ public class ScriptCacheImpl implements ScriptCache, ResourceChangeListener, Ext @Reference private ThreadPoolManager threadPoolManager; + @Reference + private SlingScriptEngineManager slingScriptEngineManager; + private ThreadPool threadPool; private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); private final Lock readLock = rwl.readLock(); @@ -284,27 +284,17 @@ public class ScriptCacheImpl implements ScriptCache, ResourceChangeListener, Ext active = false; } - protected void bindScriptEngineFactory(ScriptEngineFactory scriptEngineFactory) { - ScriptEngine engine = scriptEngineFactory.getScriptEngine(); - if (engine instanceof Compilable) { - /** - * we only care about creating an EventHandler that monitors scripts generated by script engines which implement Compilable - */ - for (String extension : scriptEngineFactory.getExtensions()) { - extensions.add(extension); - } - if (active) { - configureCache(); + @Override + public void handleEvent(Event event) { + extensions.clear(); + for (ScriptEngineFactory factory : slingScriptEngineManager.getEngineFactories()) { + ScriptEngine scriptEngine = factory.getScriptEngine(); + if (scriptEngine instanceof Compilable) { + extensions.addAll(factory.getExtensions()); + if (active) { + configureCache(); + } } } } - - protected void unbindScriptEngineFactory(ScriptEngineFactory scriptEngineFactory) { - for (String extension : scriptEngineFactory.getExtensions()) { - extensions.remove(extension); - } - if (active) { - configureCache(); - } - } } diff --git a/src/main/java/org/apache/sling/scripting/core/impl/ScriptEngineConsolePlugin.java b/src/main/java/org/apache/sling/scripting/core/impl/ScriptEngineConsolePlugin.java index 59b2658..1b88807 100644 --- a/src/main/java/org/apache/sling/scripting/core/impl/ScriptEngineConsolePlugin.java +++ b/src/main/java/org/apache/sling/scripting/core/impl/ScriptEngineConsolePlugin.java @@ -18,7 +18,9 @@ */ package org.apache.sling.scripting.core.impl; +import java.io.IOException; import java.io.PrintWriter; +import java.util.Arrays; import java.util.Dictionary; import java.util.Hashtable; import java.util.Iterator; @@ -26,57 +28,59 @@ import java.util.List; import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; - +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.felix.webconsole.AbstractWebConsolePlugin; +import org.apache.felix.webconsole.WebConsoleConstants; +import org.apache.sling.scripting.core.impl.jsr223.SlingScriptEngineManager; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceRegistration; - -public class ScriptEngineConsolePlugin { - - // --------- setup and shutdown - - private static ScriptEngineConsolePlugin INSTANCE; - - static void initPlugin(BundleContext context, - ScriptEngineManagerFactory scriptEngineManagerFactory) { - if (INSTANCE == null) { - ScriptEngineConsolePlugin tmp = new ScriptEngineConsolePlugin( - scriptEngineManagerFactory); - tmp.activate(context); - INSTANCE = tmp; - } - } - - static void destroyPlugin() { - if (INSTANCE != null) { - try { - INSTANCE.deactivate(); - } finally { - INSTANCE = null; - } - } - } - - private ServiceRegistration serviceRegistration; - - private final ScriptEngineManagerFactory scriptEngineManagerFactory; - - // private constructor to force using static setup and shutdown - private ScriptEngineConsolePlugin( - ScriptEngineManagerFactory scriptEngineManagerFactory) { - this.scriptEngineManagerFactory = scriptEngineManagerFactory; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +@Component( + property = { + Constants.SERVICE_DESCRIPTION + "=Web Console Plugin for ScriptEngine implementations", + Constants.SERVICE_VENDOR + "=The Apache Software Foundation", + WebConsoleConstants.PLUGIN_LABEL + "=" + ScriptEngineConsolePlugin.CONSOLE_LABEL, + WebConsoleConstants.PLUGIN_TITLE + "=" + ScriptEngineConsolePlugin.CONSOLE_TITLE, + WebConsoleConstants.CONFIG_PRINTER_MODES + "=always", + WebConsoleConstants.PLUGIN_CATEGORY + "=Status" + }, + service = { Servlet.class } +) +public class ScriptEngineConsolePlugin extends AbstractWebConsolePlugin { + + public static final String CONSOLE_LABEL = "slingscripting"; + public static final String CONSOLE_TITLE = "Script Engines"; + + @Reference + private SlingScriptEngineManager slingScriptEngineManager; + + @Override + public String getTitle() { + return CONSOLE_TITLE; } - public String getTitle() { - return "Script Engines"; + @Override + public String getLabel() { + return CONSOLE_LABEL; } - public void printConfiguration(final PrintWriter pw) { + @Override + protected void renderContent(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) + throws IOException { + PrintWriter pw = httpServletResponse.getWriter(); + pw.println("<div id='content' class='ui-widget'><br>"); + pw.println("<pre>"); pw.println("Available Script Engines"); pw.println("========================"); - ScriptEngineManager manager = scriptEngineManagerFactory.getScriptEngineManager(); - List<?> factories = manager.getEngineFactories(); + List<?> factories = slingScriptEngineManager.getEngineFactories(); for (Iterator<?> fi = factories.iterator(); fi.hasNext();) { final ScriptEngineFactory factory = (ScriptEngineFactory) fi.next(); @@ -100,6 +104,8 @@ public class ScriptEngineConsolePlugin { pw.print("- Names : "); printArray(pw, factory.getNames()); } + pw.println("</pre>"); + pw.println("</div>"); } private void printArray(PrintWriter pw, List<?> values) { @@ -116,25 +122,4 @@ public class ScriptEngineConsolePlugin { } } - public void activate(BundleContext context) { - final Dictionary<String, Object> props = new Hashtable<String, Object>(); - props.put(Constants.SERVICE_DESCRIPTION, - "Web Console Plugin for ScriptEngine implementations"); - props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation"); - props.put(Constants.SERVICE_PID, getClass().getName()); - - props.put("felix.webconsole.label", "slingscripting"); - props.put("felix.webconsole.title", "Script Engines"); - props.put("felix.webconsole.configprinter.modes", "always"); - - serviceRegistration = context.registerService( - this.getClass().getName(), this, props); - } - - public void deactivate() { - if (serviceRegistration != null) { - serviceRegistration.unregister(); - serviceRegistration = null; - } - } } diff --git a/src/main/java/org/apache/sling/scripting/core/impl/ScriptEngineManagerFactory.java b/src/main/java/org/apache/sling/scripting/core/impl/ScriptEngineManagerFactory.java deleted file mode 100644 index e851676..0000000 --- a/src/main/java/org/apache/sling/scripting/core/impl/ScriptEngineManagerFactory.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with this - * work for additional information regarding copyright ownership. The ASF - * licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package org.apache.sling.scripting.core.impl; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.util.Dictionary; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.script.ScriptEngineFactory; -import javax.script.ScriptEngineManager; - -import org.apache.sling.api.scripting.SlingScriptConstants; -import org.apache.sling.scripting.core.impl.helper.ProxyScriptEngineManager; -import org.apache.sling.scripting.core.impl.helper.SlingScriptEngineManager; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleEvent; -import org.osgi.framework.BundleListener; -import org.osgi.framework.ServiceRegistration; -import org.osgi.service.component.ComponentContext; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.annotations.ReferenceCardinality; -import org.osgi.service.component.annotations.ReferencePolicy; -import org.osgi.service.component.annotations.ReferencePolicyOption; -import org.osgi.service.event.Event; -import org.osgi.service.event.EventAdmin; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Component which exposes a ScriptEngineManager service. - * - */ -@Component(service = {}) -public class ScriptEngineManagerFactory implements BundleListener { - - private final Logger log = LoggerFactory.getLogger(ScriptEngineManagerFactory.class); - - private static final String ENGINE_FACTORY_SERVICE = "META-INF/services/" + ScriptEngineFactory.class.getName(); - - private BundleContext bundleContext; - - /** - * Event admin is optional - */ - @Reference(policy = ReferencePolicy.DYNAMIC, - policyOption = ReferencePolicyOption.GREEDY, - cardinality=ReferenceCardinality.OPTIONAL) - private volatile EventAdmin eventAdmin; - - /** - * The proxy to the actual ScriptEngineManager. This proxy is actually - * registered as the ScriptEngineManager service for the lifetime of - * this factory. - */ - private final ProxyScriptEngineManager scriptEngineManager = new ProxyScriptEngineManager(); - - private final Set<Bundle> engineSpiBundles = new HashSet<>(); - - private final Map<ScriptEngineFactory, Map<Object, Object>> engineSpiServices = new HashMap<>(); - - private ServiceRegistration scriptEngineManagerRegistration; - - /** - * Refresh the script engine manager. - */ - private void refreshScriptEngineManager() { - // create (empty) script engine manager - final ClassLoader loader = getClass().getClassLoader(); - final SlingScriptEngineManager tmp = new SlingScriptEngineManager(loader); - - // register script engines from bundles - synchronized (this.engineSpiBundles) { - for (final Bundle bundle : this.engineSpiBundles) { - registerFactories(tmp, bundle); - } - } - - // register script engines from registered services - synchronized (this.engineSpiServices) { - for (final Map.Entry<ScriptEngineFactory, Map<Object, Object>> factory : this.engineSpiServices.entrySet()) { - registerFactory(tmp, factory.getKey(), factory.getValue()); - } - } - - scriptEngineManager.setDelegatee(tmp); - - final List<ScriptEngineFactory> factories = tmp.getEngineFactories(); - for (final ScriptEngineFactory factory : factories) { - log.info("ScriptEngine {}/{} is now handling {}, {}, {}.", new Object[]{factory.getEngineName(), factory.getEngineVersion(), factory.getExtensions(), factory.getMimeTypes(), factory.getNames()}); - } - } - - @SuppressWarnings("unchecked") - private void registerFactories(final SlingScriptEngineManager mgr, final Bundle bundle) { - URL url = bundle.getEntry(ENGINE_FACTORY_SERVICE); - InputStream ins = null; - try { - ins = url.openStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(ins)); - String line; - while ((line = reader.readLine()) != null) { - if (!line.startsWith("#") && line.trim().length() > 0) { - try { - Class<ScriptEngineFactory> clazz = (Class<ScriptEngineFactory>) bundle.loadClass(line); - ScriptEngineFactory spi = clazz.newInstance(); - registerFactory(mgr, spi, null); - } catch (Throwable t) { - log.error("Cannot register ScriptEngineFactory " + line, t); - } - } - } - } catch (IOException ioe) { - // ignore - } finally { - if (ins != null) { - try { - ins.close(); - } catch (IOException ioe) { - } - } - } - } - - private void registerFactory(final SlingScriptEngineManager mgr, final ScriptEngineFactory factory, final Map<Object, Object> props) { - log.info("Adding ScriptEngine {}/{} for language {}/{}.", new Object[]{factory.getEngineName(), factory.getEngineVersion(), factory.getLanguageName(), factory.getLanguageVersion()}); - mgr.registerScriptEngineFactory(factory, props); - } - - // ---------- BundleListener interface ------------------------------------- - - @Override - public void bundleChanged(BundleEvent event) { - if (event.getType() == BundleEvent.STARTED - && event.getBundle().getEntry(ENGINE_FACTORY_SERVICE) != null) { - synchronized (this.engineSpiBundles) { - this.engineSpiBundles.add(event.getBundle()); - } - this.refreshScriptEngineManager(); - } else if (event.getType() == BundleEvent.STOPPED) { - boolean refresh; - synchronized (this.engineSpiBundles) { - refresh = this.engineSpiBundles.remove(event.getBundle()); - } - if (refresh) { - this.refreshScriptEngineManager(); - } - } - } - - // ---------- SCR integration ---------------------------------------------- - - protected void activate(ComponentContext context) { - this.bundleContext = context.getBundleContext(); - - this.bundleContext.addBundleListener(this); - - Bundle[] bundles = this.bundleContext.getBundles(); - synchronized (this.engineSpiBundles) { - for (Bundle bundle : bundles) { - if (bundle.getState() == Bundle.ACTIVE - && bundle.getEntry(ENGINE_FACTORY_SERVICE) != null) { - this.engineSpiBundles.add(bundle); - } - } - } - - // create a script engine manager - this.refreshScriptEngineManager(); - - scriptEngineManagerRegistration = this.bundleContext.registerService( - new String[] { ScriptEngineManager.class.getName(), - SlingScriptEngineManager.class.getName() }, - scriptEngineManager, new Hashtable<String, Object>()); - - org.apache.sling.scripting.core.impl.ScriptEngineConsolePlugin.initPlugin(context.getBundleContext(), this); - } - - protected void deactivate(ComponentContext context) { - org.apache.sling.scripting.core.impl.ScriptEngineConsolePlugin.destroyPlugin(); - - context.getBundleContext().removeBundleListener(this); - - if (scriptEngineManagerRegistration != null) { - scriptEngineManagerRegistration.unregister(); - scriptEngineManagerRegistration = null; - } - - synchronized ( this ) { - this.engineSpiBundles.clear(); - this.engineSpiServices.clear(); - } - - scriptEngineManager.setDelegatee(null); - - this.bundleContext = null; - } - - @Reference(service = ScriptEngineFactory.class, - policy = ReferencePolicy.DYNAMIC, - cardinality = ReferenceCardinality.MULTIPLE) - protected void bindScriptEngineFactory(final ScriptEngineFactory scriptEngineFactory, final Map<Object, Object> props) { - if (scriptEngineFactory != null) { - synchronized ( this.engineSpiServices) { - this.engineSpiServices.put(scriptEngineFactory, props); - } - - this.refreshScriptEngineManager(); - - // send event - postEvent(SlingScriptConstants.TOPIC_SCRIPT_ENGINE_FACTORY_ADDED, scriptEngineFactory); - } - } - - protected void unbindScriptEngineFactory(final ScriptEngineFactory scriptEngineFactory) { - boolean refresh; - synchronized (this.engineSpiServices) { - refresh = this.engineSpiServices.remove(scriptEngineFactory) != null; - } - - if (refresh) { - this.refreshScriptEngineManager(); - } - - // send event - postEvent(SlingScriptConstants.TOPIC_SCRIPT_ENGINE_FACTORY_REMOVED, scriptEngineFactory); - } - - private String[] toArray(final List<String> list) { - return list.toArray(new String[list.size()]); - } - - /** - * Post a notification with the EventAdmin - */ - private void postEvent(final String topic, final ScriptEngineFactory scriptEngineFactory) { - final EventAdmin localEA = this.eventAdmin; - if (localEA != null) { - final Dictionary<String, Object> props = new Hashtable<>(); - props.put(SlingScriptConstants.PROPERTY_SCRIPT_ENGINE_FACTORY_NAME, scriptEngineFactory.getEngineName()); - props.put(SlingScriptConstants.PROPERTY_SCRIPT_ENGINE_FACTORY_VERSION, scriptEngineFactory.getEngineVersion()); - props.put(SlingScriptConstants.PROPERTY_SCRIPT_ENGINE_FACTORY_EXTENSIONS, toArray(scriptEngineFactory.getExtensions())); - props.put(SlingScriptConstants.PROPERTY_SCRIPT_ENGINE_FACTORY_LANGUAGE_NAME, scriptEngineFactory.getLanguageName()); - props.put(SlingScriptConstants.PROPERTY_SCRIPT_ENGINE_FACTORY_LANGUAGE_VERSION, scriptEngineFactory.getLanguageVersion()); - props.put(SlingScriptConstants.PROPERTY_SCRIPT_ENGINE_FACTORY_MIME_TYPES, toArray(scriptEngineFactory.getMimeTypes())); - localEA.postEvent(new Event(topic, props)); - } - } - - /** - * Get the script engine manager. - * Refresh the manager if changes occurred. - */ - ScriptEngineManager getScriptEngineManager() { - return this.scriptEngineManager; - } -} diff --git a/src/main/java/org/apache/sling/scripting/core/impl/SlingScriptAdapterFactory.java b/src/main/java/org/apache/sling/scripting/core/impl/SlingScriptAdapterFactory.java index 04b6cb2..4b94191 100644 --- a/src/main/java/org/apache/sling/scripting/core/impl/SlingScriptAdapterFactory.java +++ b/src/main/java/org/apache/sling/scripting/core/impl/SlingScriptAdapterFactory.java @@ -27,7 +27,7 @@ import org.apache.sling.commons.mime.MimeTypeProvider; import org.apache.sling.scripting.api.BindingsValuesProvider; import org.apache.sling.scripting.api.BindingsValuesProvidersByContext; import org.apache.sling.scripting.api.ScriptCache; -import org.apache.sling.scripting.core.impl.helper.SlingScriptEngineManager; +import org.apache.sling.scripting.core.impl.jsr223.SlingScriptEngineManager; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.service.component.ComponentContext; diff --git a/src/main/java/org/apache/sling/scripting/core/impl/helper/ProxyScriptEngineManager.java b/src/main/java/org/apache/sling/scripting/core/impl/helper/ProxyScriptEngineManager.java deleted file mode 100644 index d699828..0000000 --- a/src/main/java/org/apache/sling/scripting/core/impl/helper/ProxyScriptEngineManager.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.sling.scripting.core.impl.helper; - -import java.util.List; -import java.util.Map; - -import javax.script.Bindings; -import javax.script.ScriptEngine; -import javax.script.ScriptEngineFactory; - -public class ProxyScriptEngineManager extends SlingScriptEngineManager { - - private SlingScriptEngineManager delegatee; - - public ProxyScriptEngineManager() { - setDelegatee(null); - } - - public void setDelegatee(SlingScriptEngineManager delegatee) { - this.delegatee = (delegatee == null) - ? new SlingScriptEngineManager() - : delegatee; - } - - public Object get(String key) { - return delegatee.get(key); - } - - public ScriptEngine getEngineByExtension(String extension) { - return delegatee.getEngineByExtension(extension); - } - - public ScriptEngine getEngineByMimeType(String mimeType) { - return delegatee.getEngineByMimeType(mimeType); - } - - public ScriptEngine getEngineByName(String shortName) { - return delegatee.getEngineByName(shortName); - } - - public List<ScriptEngineFactory> getEngineFactories() { - return delegatee.getEngineFactories(); - } - - public Map<Object, Object> getProperties(ScriptEngineFactory factory) { - return delegatee.getProperties(factory); - } - - public void put(String key, Object value) { - delegatee.put(key, value); - } - - public void registerEngineExtension(String extension, - ScriptEngineFactory factory) { - delegatee.registerEngineExtension(extension, factory); - } - - public void registerEngineMimeType(String type, ScriptEngineFactory factory) { - delegatee.registerEngineMimeType(type, factory); - } - - public void registerEngineName(String name, ScriptEngineFactory factory) { - delegatee.registerEngineName(name, factory); - } - - public void registerScriptEngineFactory(ScriptEngineFactory factory, - Map<Object, Object> props) { - delegatee.registerScriptEngineFactory(factory, props); - } - - // Livetribe JSR-223 2.0.6 API - public Bindings getGlobalScope() - { - return getBindings(); - } - - // Livetribe JSR-223 2.0.6 API - public void setGlobalScope(Bindings globalScope) - { - setBindings(globalScope); - } - - public Bindings getBindings() { - return delegatee.getBindings(); - } - - public void setBindings(Bindings bindings) { - delegatee.setBindings(bindings); - } -} diff --git a/src/main/java/org/apache/sling/scripting/core/impl/helper/SlingScriptEngineManager.java b/src/main/java/org/apache/sling/scripting/core/impl/helper/SlingScriptEngineManager.java deleted file mode 100644 index 32f727e..0000000 --- a/src/main/java/org/apache/sling/scripting/core/impl/helper/SlingScriptEngineManager.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.sling.scripting.core.impl.helper; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.script.ScriptEngineFactory; -import javax.script.ScriptEngineManager; - - -public class SlingScriptEngineManager extends ScriptEngineManager { - - private final List<ScriptEngineFactory> factories = new ArrayList<ScriptEngineFactory>(); - private final Map<ScriptEngineFactory, Map<Object, Object>> factoryProperties = new HashMap<ScriptEngineFactory, Map<Object, Object>>(); - - public SlingScriptEngineManager(ClassLoader classLoader) { - super(classLoader); - } - - public SlingScriptEngineManager() { - super(); - } - - @Override - public List<ScriptEngineFactory> getEngineFactories() { - List<ScriptEngineFactory> baseFactories = super.getEngineFactories(); - - List<ScriptEngineFactory> result = new ArrayList<ScriptEngineFactory>(); - result.addAll(factories); - result.addAll(baseFactories); - return result; - } - - public Map<Object, Object> getProperties(ScriptEngineFactory factory) { - return factoryProperties.get(factory); - } - - public void registerScriptEngineFactory(ScriptEngineFactory factory, Map<Object, Object> props) { - for (Object ext : factory.getExtensions()) { - registerEngineExtension((String) ext, factory); - } - - for (Object mime : factory.getMimeTypes()) { - registerEngineMimeType((String) mime, factory); - } - - for (Object name : factory.getNames()) { - registerEngineName((String) name, factory); - } - - factories.add(factory); - - if (props != null) { - factoryProperties.put(factory, props); - } - } - -} diff --git a/src/main/java/org/apache/sling/scripting/core/impl/jsr223/SlingScriptEngineManager.java b/src/main/java/org/apache/sling/scripting/core/impl/jsr223/SlingScriptEngineManager.java new file mode 100644 index 0000000..8c52960 --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/core/impl/jsr223/SlingScriptEngineManager.java @@ -0,0 +1,320 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you under the Apache License, Version 2.0 (the + ~ "License"); you may not use this file except in compliance + ~ with the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, + ~ software distributed under the License is distributed on an + ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + ~ KIND, either express or implied. See the License for the + ~ specific language governing permissions and limitations + ~ under the License. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +package org.apache.sling.scripting.core.impl.jsr223; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptEngineManager; + +import org.apache.sling.api.scripting.SlingScriptConstants; +import org.apache.sling.commons.osgi.PropertiesUtil; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.BundleListener; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceReference; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventAdmin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Component( + service = {ScriptEngineManager.class, SlingScriptEngineManager.class}, + reference = @Reference( + name = "ScriptEngineFactory", + bind = "bindScriptEngineFactory", + unbind = "unbindScriptEngineFactory", + service = ScriptEngineFactory.class, + cardinality = ReferenceCardinality.MULTIPLE, + policy = ReferencePolicy.DYNAMIC + ) +) +public class SlingScriptEngineManager extends ScriptEngineManager implements BundleListener { + + public static final String EVENT_TOPIC_SCRIPT_MANAGER_UPDATED = + "org/apache/sling/scripting/core/impl/jsr223/SlingScriptEngineManager/UPDATED"; + public static final String ENGINE_FACTORY_SERVICE = "META-INF/services/" + ScriptEngineFactory.class.getName(); + + private static final Logger LOG = LoggerFactory.getLogger(SlingScriptEngineManager.class); + + private final Set<Bundle> engineSpiBundles = new HashSet<>(); + private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private final Map<ScriptEngineFactory, Map<String, Object>> factoriesProperties = new HashMap<>(); + private final Set<ServiceReference<ScriptEngineFactory>> serviceReferences = new HashSet<>(); + + private ScriptEngineManager internalManager = new ScriptEngineManager(SlingScriptEngineManager.class.getClassLoader()); + private SortedSet<SortableScriptEngineFactory> factories = new TreeSet<>(); + private ComponentContext componentContext; + + @Reference(policy = ReferencePolicy.DYNAMIC, + policyOption = ReferencePolicyOption.GREEDY, + cardinality = ReferenceCardinality.OPTIONAL) + private volatile EventAdmin eventAdmin; + + @Override + public ScriptEngine getEngineByName(String shortName) { + readWriteLock.readLock().lock(); + try { + return internalManager.getEngineByName(shortName); + } finally { + readWriteLock.readLock().unlock(); + } + } + + @Override + public ScriptEngine getEngineByExtension(String extension) { + readWriteLock.readLock().lock(); + try { + return internalManager.getEngineByExtension(extension); + } finally { + readWriteLock.readLock().unlock(); + } + } + + @Override + public ScriptEngine getEngineByMimeType(String mimeType) { + readWriteLock.readLock().lock(); + try { + return internalManager.getEngineByMimeType(mimeType); + } finally { + readWriteLock.readLock().unlock(); + } + } + + @Override + public List<ScriptEngineFactory> getEngineFactories() { + readWriteLock.readLock().lock(); + try { + ArrayList<ScriptEngineFactory> list = new ArrayList<>(factories.size()); + list.addAll(factories); + return Collections.unmodifiableList(list); + } finally { + readWriteLock.readLock().unlock(); + } + } + + @Override + public void registerEngineName(String name, ScriptEngineFactory factory) { + readWriteLock.writeLock().lock(); + try { + internalManager.registerEngineName(name, factory); + } finally { + readWriteLock.writeLock().unlock(); + } + } + + @Override + public void registerEngineMimeType(String type, ScriptEngineFactory factory) { + readWriteLock.writeLock().lock(); + try { + internalManager.registerEngineMimeType(type, factory); + } finally { + readWriteLock.writeLock().unlock(); + } + } + + @Override + public void registerEngineExtension(String extension, ScriptEngineFactory factory) { + readWriteLock.writeLock().lock(); + try { + internalManager.registerEngineExtension(extension, factory); + } finally { + readWriteLock.writeLock().unlock(); + } + } + + @Override + public void bundleChanged(BundleEvent event) { + if (event.getType() == BundleEvent.STARTED + && event.getBundle().getEntry(ENGINE_FACTORY_SERVICE) != null) { + synchronized (this.engineSpiBundles) { + this.engineSpiBundles.add(event.getBundle()); + } + updateFactories(); + } else if (event.getType() == BundleEvent.STOPPED) { + boolean refresh; + synchronized (this.engineSpiBundles) { + refresh = this.engineSpiBundles.remove(event.getBundle()); + } + if (refresh) { + updateFactories(); + } + } + } + + public Map<String, Object> getProperties(ScriptEngineFactory factory) { + readWriteLock.readLock().lock(); + try { + return factoriesProperties.get(factory); + } finally { + readWriteLock.readLock().unlock(); + } + } + + @Activate + private void activate(ComponentContext componentContext) { + this.componentContext = componentContext; + updateFactories(); + } + + private void bindScriptEngineFactory(final ServiceReference<ScriptEngineFactory> serviceReference, + final ScriptEngineFactory factory) { + synchronized (this.serviceReferences) { + serviceReferences.add(serviceReference); + } + updateFactories(); + postEvent(SlingScriptConstants.TOPIC_SCRIPT_ENGINE_FACTORY_ADDED, factory); + } + + private void unbindScriptEngineFactory(final ServiceReference<ScriptEngineFactory> serviceReference, final ScriptEngineFactory + factory) { + synchronized (this.serviceReferences) { + serviceReferences.remove(serviceReference); + if (componentContext != null) { + componentContext.getBundleContext().ungetService(serviceReference); + } + } + updateFactories(); + postEvent(SlingScriptConstants.TOPIC_SCRIPT_ENGINE_FACTORY_REMOVED, factory); + } + + private void updateFactories() { + readWriteLock.writeLock().lock(); + try { + factories = new TreeSet<>(); + internalManager = new ScriptEngineManager(SlingScriptEngineManager.class.getClassLoader()); + long fakeBundleIdCounter = Long.MIN_VALUE; + // first add the platform factories + for (ScriptEngineFactory factory : internalManager.getEngineFactories()) { + SortableScriptEngineFactory ssef = new SortableScriptEngineFactory(factory, fakeBundleIdCounter++, 0); + factories.add(ssef); + } + // then factories from SPI Bundles + for (Bundle bundle : engineSpiBundles) { + URL url = bundle.getEntry(ENGINE_FACTORY_SERVICE); + InputStream ins = null; + try { + ins = url.openStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(ins, StandardCharsets.UTF_8)); + String line; + while ((line = reader.readLine()) != null) { + if (!line.startsWith("#") && line.trim().length() > 0) { + try { + Class<ScriptEngineFactory> clazz = (Class<ScriptEngineFactory>) bundle.loadClass(line); + SortableScriptEngineFactory ssef = new SortableScriptEngineFactory(clazz.getDeclaredConstructor() + .newInstance(), fakeBundleIdCounter++, 0); + factories.add(ssef); + } catch (Throwable t) { + LOG.error("Cannot register ScriptEngineFactory " + line, t); + } + } + } + } catch (IOException ioe) { + LOG.error("Unable to process bundle " + bundle.getSymbolicName(), ioe); + } finally { + if (ins != null) { + try { + ins.close(); + } catch (IOException ioe) { + LOG.error("Unable to release stream resource.", ioe); + } + } + } + } + // and finally factories registered as OSGi services + if (componentContext != null) { + factoriesProperties.clear(); + for (ServiceReference<ScriptEngineFactory> serviceReference : serviceReferences) { + ScriptEngineFactory scriptEngineFactory = componentContext.getBundleContext().getService(serviceReference); + SortableScriptEngineFactory sortableScriptEngineFactory = + new SortableScriptEngineFactory(scriptEngineFactory, serviceReference.getBundle().getBundleId(), + PropertiesUtil.toInteger(serviceReference.getProperty(Constants.SERVICE_RANKING), 0)); + factories.add(sortableScriptEngineFactory); + Map<String, Object> factoryProperties = new HashMap<>(serviceReference.getPropertyKeys().length); + for (String key : serviceReference.getPropertyKeys()) { + factoryProperties.put(key, serviceReference.getProperty(key)); + } + factoriesProperties.put(scriptEngineFactory, factoryProperties); + } + } + // register the associations at the end, so that the priority sorting is taken into consideration + for (ScriptEngineFactory factory : factories) { + registerAssociations(factory); + } + if (eventAdmin != null) { + eventAdmin.postEvent(new Event(EVENT_TOPIC_SCRIPT_MANAGER_UPDATED, Collections.EMPTY_MAP)); + } + } finally { + readWriteLock.writeLock().unlock(); + } + } + + private void registerAssociations(ScriptEngineFactory factory) { + for (String extension : factory.getExtensions()) { + internalManager.registerEngineExtension(extension, factory); + } + for (String mimeType : factory.getMimeTypes()) { + internalManager.registerEngineMimeType(mimeType, factory); + } + for (String name : factory.getNames()) { + internalManager.registerEngineName(name, factory); + } + } + + private void postEvent(final String topic, final ScriptEngineFactory scriptEngineFactory) { + if (eventAdmin != null) { + final Dictionary<String, Object> props = new Hashtable<>(); + props.put(SlingScriptConstants.PROPERTY_SCRIPT_ENGINE_FACTORY_NAME, scriptEngineFactory.getEngineName()); + props.put(SlingScriptConstants.PROPERTY_SCRIPT_ENGINE_FACTORY_VERSION, scriptEngineFactory.getEngineVersion()); + props.put(SlingScriptConstants.PROPERTY_SCRIPT_ENGINE_FACTORY_EXTENSIONS, scriptEngineFactory.getExtensions().toArray(new + String[0])); + props.put(SlingScriptConstants.PROPERTY_SCRIPT_ENGINE_FACTORY_LANGUAGE_NAME, scriptEngineFactory.getLanguageName()); + props.put(SlingScriptConstants.PROPERTY_SCRIPT_ENGINE_FACTORY_LANGUAGE_VERSION, scriptEngineFactory.getLanguageVersion()); + props.put(SlingScriptConstants.PROPERTY_SCRIPT_ENGINE_FACTORY_MIME_TYPES, scriptEngineFactory.getMimeTypes().toArray(new + String[0])); + eventAdmin.postEvent(new Event(topic, props)); + } + } +} diff --git a/src/main/java/org/apache/sling/scripting/core/impl/jsr223/SortableScriptEngineFactory.java b/src/main/java/org/apache/sling/scripting/core/impl/jsr223/SortableScriptEngineFactory.java new file mode 100644 index 0000000..b04573f --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/core/impl/jsr223/SortableScriptEngineFactory.java @@ -0,0 +1,134 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you under the Apache License, Version 2.0 (the + ~ "License"); you may not use this file except in compliance + ~ with the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, + ~ software distributed under the License is distributed on an + ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + ~ KIND, either express or implied. See the License for the + ~ specific language governing permissions and limitations + ~ under the License. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +package org.apache.sling.scripting.core.impl.jsr223; + +import java.util.List; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; + +public class SortableScriptEngineFactory implements ScriptEngineFactory, Comparable { + + private final ScriptEngineFactory delegate; + private final int serviceRanking; + private final long bundleId; + + /** + * Constructor for implicit {@link ScriptEngineFactory} provided by the platform. + * + * @param delegate the actual {@link ScriptEngineFactory} + */ + SortableScriptEngineFactory(ScriptEngineFactory delegate) { + this.delegate = delegate; + serviceRanking = 0; + bundleId = 0; + } + + /** + * Constructor for OSGi registered {@link ScriptEngineFactory} instances. + * + * @param delegate the actual {@link ScriptEngineFactory} + * @param bundleId the bundle id of the bundle registering the {@link ScriptEngineFactory} + * @param serviceRanking the service ranking of the {@link ScriptEngineFactory} + */ + SortableScriptEngineFactory(ScriptEngineFactory delegate, long bundleId, int serviceRanking) { + this.delegate = delegate; + this.bundleId = bundleId; + this.serviceRanking = serviceRanking; + } + + @Override + public String getEngineName() { + return delegate.getEngineName(); + } + + @Override + public String getEngineVersion() { + return delegate.getEngineVersion(); + } + + @Override + public List<String> getExtensions() { + return delegate.getExtensions(); + } + + @Override + public List<String> getMimeTypes() { + return delegate.getMimeTypes(); + } + + @Override + public List<String> getNames() { + return delegate.getNames(); + } + + @Override + public String getLanguageName() { + return delegate.getLanguageName(); + } + + @Override + public String getLanguageVersion() { + return delegate.getLanguageVersion(); + } + + @Override + public Object getParameter(String key) { + return delegate.getParameter(key); + } + + @Override + public String getMethodCallSyntax(String obj, String m, String... args) { + return delegate.getMethodCallSyntax(obj, m, args); + } + + @Override + public String getOutputStatement(String toDisplay) { + return delegate.getOutputStatement(toDisplay); + } + + @Override + public String getProgram(String... statements) { + return delegate.getProgram(statements); + } + + @Override + public ScriptEngine getScriptEngine() { + return delegate.getScriptEngine(); + } + + @Override + public int compareTo(Object o) { + SortableScriptEngineFactory other = (SortableScriptEngineFactory) o; + if (equals(other)) { + return 0; + } + if (serviceRanking == other.serviceRanking) { + if (bundleId > other.bundleId) { + return 1; + } else if (bundleId == other.bundleId) { + return 0; + } + return -1; + } else if (serviceRanking > other.serviceRanking) { + return 1; + } + return -1; + } +} diff --git a/src/test/java/org/apache/sling/scripting/core/ScriptHelperTest.java b/src/test/java/org/apache/sling/scripting/core/ScriptHelperTest.java index af578ec..646a3eb 100644 --- a/src/test/java/org/apache/sling/scripting/core/ScriptHelperTest.java +++ b/src/test/java/org/apache/sling/scripting/core/ScriptHelperTest.java @@ -26,7 +26,7 @@ import static org.junit.Assert.fail; import java.util.Dictionary; import java.util.Hashtable; -import org.apache.sling.testing.mock.sling.junit.SlingContext; +import org.apache.sling.testing.mock.osgi.junit.OsgiContext; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -35,7 +35,7 @@ import org.osgi.framework.Constants; public class ScriptHelperTest { @Rule - public SlingContext sling = new SlingContext(); + public OsgiContext sling = new OsgiContext(); private ScriptHelper sh; private final int [] RANKINGS = { 42, 62, -12, 76, -123, 0, 7432, -21 }; @@ -74,4 +74,4 @@ public class ScriptHelperTest { assertEquals(RANKINGS.length, svc.length); assertHigherRankingComesFirst(svc); } -} \ No newline at end of file +} diff --git a/src/test/java/org/apache/sling/scripting/core/impl/ScriptEngineManagerFactoryTest.java b/src/test/java/org/apache/sling/scripting/core/impl/ScriptEngineManagerFactoryTest.java deleted file mode 100644 index de8c85d..0000000 --- a/src/test/java/org/apache/sling/scripting/core/impl/ScriptEngineManagerFactoryTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with this - * work for additional information regarding copyright ownership. The ASF - * licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package org.apache.sling.scripting.core.impl; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Dictionary; - -import javax.script.ScriptEngineManager; - -import org.jmock.Expectations; -import org.jmock.Mockery; -import org.jmock.integration.junit4.JMock; -import org.jmock.integration.junit4.JUnit4Mockery; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleEvent; -import org.osgi.framework.BundleListener; -import org.osgi.framework.ServiceListener; -import org.osgi.framework.ServiceReference; -import org.osgi.framework.ServiceRegistration; -import org.osgi.service.component.ComponentContext; - -/** - * Test of the ScriptEngineManagerFactory. - */ -@RunWith(JMock.class) -public class ScriptEngineManagerFactoryTest { - - private static Class<?> SCRIPT_ENGINE_FACTORY = DummyScriptEngineFactory.class; - - private Mockery context = new JUnit4Mockery(); - - private ComponentContext componentCtx; - - private BundleContext bundleCtx; - - @Before - public void setup() throws Exception { - componentCtx = context.mock(ComponentContext.class); - bundleCtx = context.mock(BundleContext.class); - context.checking(new Expectations(){{ - atLeast(1).of(componentCtx).getBundleContext(); - will(returnValue(bundleCtx)); - - allowing(bundleCtx).createFilter(with(any(String.class))); - allowing(bundleCtx).addServiceListener(with(any(ServiceListener.class))); - allowing(bundleCtx).addServiceListener(with(any(ServiceListener.class)), with(any(String.class))); - allowing(bundleCtx).getServiceReferences(with(any(String.class)), with(aNull(String.class))); - allowing(bundleCtx).getServiceReferences(with(aNull(String.class)), with(aNull(String.class))); - allowing(bundleCtx).getServiceReferences(with(any(String.class)), with(any(String.class))); - allowing(bundleCtx).getServiceReferences(with(aNull(String.class)), with(any(String.class))); - - one(bundleCtx).addBundleListener(with(any(BundleListener.class))); - one(bundleCtx).getBundles(); - will(returnValue(new Bundle[0])); - - allowing(bundleCtx).registerService(with(equal("org.apache.sling.scripting.core.impl.ScriptEngineConsolePlugin")), with(any(Object.class)), with(any(Dictionary.class))); - will(returnValue(new MockServiceRegistration())); - - - }}); - } - - - @Test - public void checkNonNullManagerAfterActivate() throws Exception { - context.checking(new Expectations(){{ - one(bundleCtx).registerService(with(equal(new String[] {"javax.script.ScriptEngineManager", "org.apache.sling.scripting.core.impl.helper.SlingScriptEngineManager"})), with(any(Object.class)), with(any(Dictionary.class))); - will(returnValue(new MockServiceRegistration())); - }}); - - ScriptEngineManagerFactory factory = new ScriptEngineManagerFactory(); - factory.activate(componentCtx); - - assertNotNull(factory.getScriptEngineManager()); - } - - @Test - public void checkAddingScriptBundle() throws Exception { - context.checking(new Expectations(){{ - exactly(1).of(bundleCtx).registerService(with(equal(new String[] {"javax.script.ScriptEngineManager", "org.apache.sling.scripting.core.impl.helper.SlingScriptEngineManager"})), with(any(Object.class)), with(any(Dictionary.class))); - will(returnValue(new MockServiceRegistration())); - }}); - - ScriptEngineManagerFactory factory = new ScriptEngineManagerFactory(); - factory.activate(componentCtx); - - ScriptEngineManager first = factory.getScriptEngineManager(); - - assertNull(first.getEngineByName("dummy")); - - final Bundle bundle = context.mock(Bundle.class); - - final File factoryFile = createFactoryFile(); - - context.checking(new Expectations() {{ - - atLeast(1).of(bundle).getEntry("META-INF/services/javax.script.ScriptEngineFactory"); - will(returnValue(factoryFile.toURI().toURL())); - - atLeast(1).of(bundle).loadClass(SCRIPT_ENGINE_FACTORY.getName()); - will(returnValue(SCRIPT_ENGINE_FACTORY)); - }}); - - factory.bundleChanged(new BundleEvent(BundleEvent.STARTED, bundle)); - - ScriptEngineManager second = factory.getScriptEngineManager(); - - assertNotNull(second.getEngineByName("dummy")); - } - - private File createFactoryFile() throws IOException { - File tempFile = File.createTempFile("scriptEngine", "tmp"); - tempFile.deleteOnExit(); - - FileOutputStream fos = null; - try { - fos = new FileOutputStream(tempFile); - fos.write("#I'am a test-comment\n".getBytes()); - fos.write(SCRIPT_ENGINE_FACTORY.getName().getBytes()); - } finally { - if (fos != null) { - fos.close(); - } - } - return tempFile; - } - - private class MockServiceRegistration implements ServiceRegistration { - - public ServiceReference getReference() { - throw new UnsupportedOperationException(); - } - - @SuppressWarnings("unchecked") - public void setProperties(Dictionary properties) { - // NO-OP - } - - public void unregister() { - // NO-OP - } - - } - -} diff --git a/src/test/java/org/apache/sling/scripting/core/impl/DummyScriptEngineFactory.java b/src/test/java/org/apache/sling/scripting/core/impl/jsr223/DummyScriptEngineFactory.java similarity index 76% rename from src/test/java/org/apache/sling/scripting/core/impl/DummyScriptEngineFactory.java rename to src/test/java/org/apache/sling/scripting/core/impl/jsr223/DummyScriptEngineFactory.java index 3c67591..9a36ecb 100644 --- a/src/test/java/org/apache/sling/scripting/core/impl/DummyScriptEngineFactory.java +++ b/src/test/java/org/apache/sling/scripting/core/impl/jsr223/DummyScriptEngineFactory.java @@ -1,20 +1,22 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with this - * work for additional information regarding copyright ownership. The ASF - * licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package org.apache.sling.scripting.core.impl; +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you under the Apache License, Version 2.0 (the + ~ "License"); you may not use this file except in compliance + ~ with the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, + ~ software distributed under the License is distributed on an + ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + ~ KIND, either express or implied. See the License for the + ~ specific language governing permissions and limitations + ~ under the License. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +package org.apache.sling.scripting.core.impl.jsr223; import java.io.Reader; import java.util.Arrays; diff --git a/src/test/java/org/apache/sling/scripting/core/impl/jsr223/SlingScriptEngineManagerTest.java b/src/test/java/org/apache/sling/scripting/core/impl/jsr223/SlingScriptEngineManagerTest.java new file mode 100644 index 0000000..a6df3c4 --- /dev/null +++ b/src/test/java/org/apache/sling/scripting/core/impl/jsr223/SlingScriptEngineManagerTest.java @@ -0,0 +1,208 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you under the Apache License, Version 2.0 (the + ~ "License"); you may not use this file except in compliance + ~ with the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, + ~ software distributed under the License is distributed on an + ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + ~ KIND, either express or implied. See the License for the + ~ specific language governing permissions and limitations + ~ under the License. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +package org.apache.sling.scripting.core.impl.jsr223; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.util.Collections; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptEngineManager; + +import org.apache.sling.testing.mock.osgi.junit.OsgiContext; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventConstants; +import org.osgi.service.event.EventHandler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class SlingScriptEngineManagerTest { + + private static Class<?> SCRIPT_ENGINE_FACTORY = DummyScriptEngineFactory.class; + + @Rule + public final OsgiContext context = new OsgiContext(); + + + @Before + public void setUp() { + context.registerInjectActivateService(new SlingScriptEngineManager()); + } + + @Test + public void testPlatformScriptEngines() { + ScriptEngineManager scriptEngineManager = context.getService(ScriptEngineManager.class); + assertNotNull("Expected a ScriptEngineManager would be already registered.", scriptEngineManager); + assertEquals("The ScriptEngineManager should have had 1 ScriptEngineFactory registered.", 1, scriptEngineManager + .getEngineFactories().size()); + } + + @Test + public void testOSGiRegisteredFactoriesDifferentServiceRanking() throws Exception { + int expectedEvents = 3; + CountDownLatch latch = new CountDownLatch(expectedEvents); + TestEventHandler eventHandler = new TestEventHandler + (latch, "org/apache/sling/scripting/core/impl/jsr223/SlingScriptEngineManager/UPDATED"); + context.registerService( + EventHandler.class, eventHandler, + new HashMap<String, Object>() {{ + put(EventConstants.EVENT_TOPIC, "org/apache/sling/scripting/core/impl/jsr223/SlingScriptEngineManager/*"); + }} + ); + + ScriptEngineFactory f1 = mockScriptEngineFactory("f1", "1.0", Collections.singletonList("f1"), "f1", "1.0", Collections + .singletonList("text")); + ScriptEngineFactory f2 = mockScriptEngineFactory("f2", "1.0", Collections.singletonList("f2"), "f2", "1.0", Collections + .singletonList("text")); + + ServiceRegistration<ScriptEngineFactory> f1SR = context.bundleContext().registerService(ScriptEngineFactory.class, f1, new + Hashtable<String, Object>() {{ + put(Constants.SERVICE_RANKING, 2); + }}); + context.bundleContext().registerService(ScriptEngineFactory.class, f2, new + Hashtable<String, Object>() {{ + put(Constants.SERVICE_RANKING, 1); + }}); + + ScriptEngineManager scriptEngineManager = context.getService(ScriptEngineManager.class); + assertNotNull("Expected a ScriptEngineManager would be already registered.", scriptEngineManager); + List<ScriptEngineFactory> factories = scriptEngineManager.getEngineFactories(); + assertEquals("The ScriptEngineManager should have had 3 ScriptEngineFactories registered.", 3, factories.size()); + assertEquals(f1.getEngineName(), factories.get(2).getEngineName()); + assertEquals(f2.getEngineName(), factories.get(1).getEngineName()); + + SlingScriptEngineManager slingScriptEngineManager = context.getService(SlingScriptEngineManager.class); + assertEquals(2, slingScriptEngineManager.getProperties(f1).get(Constants.SERVICE_RANKING)); + + f1SR.unregister(); + + factories = scriptEngineManager.getEngineFactories(); + assertEquals("The ScriptEngineManager should have had 2 ScriptEngineFactories registered.", 2, factories.size()); + assertEquals(f2.getEngineName(), factories.get(1).getEngineName()); + + assertEquals(f2, scriptEngineManager.getEngineByName("f2").getFactory()); + assertEquals(f2, scriptEngineManager.getEngineByExtension("f2").getFactory()); + assertEquals(f2, scriptEngineManager.getEngineByMimeType("text").getFactory()); + + latch.await(2, TimeUnit.SECONDS); + assertEquals("Expected a different number of processed " + SlingScriptEngineManager.EVENT_TOPIC_SCRIPT_MANAGER_UPDATED + " events.", + expectedEvents, eventHandler.processedEvents); + } + + @Test + public void testBundledScriptEngineFactory() throws Exception { + URL url = createFactoryFile().toURI().toURL(); + Bundle bundle = mock(Bundle.class); + when(bundle.getEntry(SlingScriptEngineManager.ENGINE_FACTORY_SERVICE)).thenReturn(url); + when(bundle.loadClass(SCRIPT_ENGINE_FACTORY.getName())).thenAnswer(new Answer<Class>() { + @Override + public Class answer(InvocationOnMock invocation) { + return SCRIPT_ENGINE_FACTORY; + } + }); + + BundleEvent bundleEvent = new BundleEvent(BundleEvent.STARTED, bundle); + SlingScriptEngineManager slingScriptEngineManager = context.getService(SlingScriptEngineManager.class); + assertNotNull("Expected that the SlingScriptEngineManager would already be registered.", slingScriptEngineManager); + slingScriptEngineManager.bundleChanged(bundleEvent); + List<ScriptEngineFactory> factories = slingScriptEngineManager.getEngineFactories(); + assertEquals("Expected 2 ScriptEngineFactories.", 2, factories.size()); + assertEquals("Dummy Scripting Engine", factories.get(1).getEngineName()); + + bundleEvent = new BundleEvent(BundleEvent.STOPPED, bundle); + slingScriptEngineManager.bundleChanged(bundleEvent); + factories = slingScriptEngineManager.getEngineFactories(); + assertEquals("Expected 1 ScriptEngineFactory.", 1, factories.size()); + assertEquals("Oracle Nashorn", factories.get(0).getEngineName()); + } + + private ScriptEngineFactory mockScriptEngineFactory(String engineName, String engineVersion, List<String> extensions, String + languageName, String languageVersion, List<String> mimeTypes) { + ScriptEngineFactory factory = mock(ScriptEngineFactory.class); + when(factory.getEngineName()).thenReturn(engineName); + when(factory.getNames()).thenReturn(Collections.singletonList(engineName)); + when(factory.getEngineVersion()).thenReturn(engineVersion); + when(factory.getExtensions()).thenReturn(extensions); + when(factory.getLanguageName()).thenReturn(languageName); + when(factory.getLanguageVersion()).thenReturn(languageVersion); + when(factory.getMimeTypes()).thenReturn(mimeTypes); + ScriptEngine scriptEngine = mock(ScriptEngine.class); + when(factory.getScriptEngine()).thenReturn(scriptEngine); + when(scriptEngine.getFactory()).thenReturn(factory); + return factory; + } + + private File createFactoryFile() throws IOException { + File tempFile = File.createTempFile("scriptEngine", "tmp"); + tempFile.deleteOnExit(); + + FileOutputStream fos = null; + try { + fos = new FileOutputStream(tempFile); + fos.write("#I'm a test-comment\n".getBytes()); + fos.write(SCRIPT_ENGINE_FACTORY.getName().getBytes()); + } finally { + if (fos != null) { + fos.close(); + } + } + return tempFile; + } + + + private static class TestEventHandler implements EventHandler { + + String topic; + CountDownLatch latch; + int processedEvents = 0; + + public TestEventHandler(CountDownLatch latch, String topic) { + this.topic = topic; + this.latch = latch; + } + + @Override + public void handleEvent(Event event) { + if (event.getTopic().equals(topic)) { + processedEvents++; + latch.countDown(); + } + } + } +} diff --git a/src/test/java/org/apache/sling/scripting/core/impl/jsr223/SortableScriptEngineFactoryTest.java b/src/test/java/org/apache/sling/scripting/core/impl/jsr223/SortableScriptEngineFactoryTest.java new file mode 100644 index 0000000..e220bcf --- /dev/null +++ b/src/test/java/org/apache/sling/scripting/core/impl/jsr223/SortableScriptEngineFactoryTest.java @@ -0,0 +1,174 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you under the Apache License, Version 2.0 (the + ~ "License"); you may not use this file except in compliance + ~ with the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, + ~ software distributed under the License is distributed on an + ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + ~ KIND, either express or implied. See the License for the + ~ specific language governing permissions and limitations + ~ under the License. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +package org.apache.sling.scripting.core.impl.jsr223; + +import java.util.Collections; +import java.util.List; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class SortableScriptEngineFactoryTest { + + @Test + public void testDelegateConstructor() { + ScriptEngineFactory delegate = mock(ScriptEngineFactory.class); + SortableScriptEngineFactory sortableScriptEngineFactory = new SortableScriptEngineFactory(delegate); + assertEquals(0, sortableScriptEngineFactory.compareTo(getCompareFactory(0, 0))); + } + + @Test + public void getEngineName() { + String answer = "answer"; + ScriptEngineFactory scriptEngineFactory = mock(ScriptEngineFactory.class); + when(scriptEngineFactory.getEngineName()).thenReturn(answer); + SortableScriptEngineFactory sortableScriptEngineFactory = new SortableScriptEngineFactory(scriptEngineFactory, 0, 0); + assertEquals(answer, sortableScriptEngineFactory.getEngineName()); + } + + @Test + public void getEngineVersion() { + String answer = "answer"; + ScriptEngineFactory scriptEngineFactory = mock(ScriptEngineFactory.class); + when(scriptEngineFactory.getEngineVersion()).thenReturn(answer); + SortableScriptEngineFactory sortableScriptEngineFactory = new SortableScriptEngineFactory(scriptEngineFactory, 0, 0); + assertEquals(answer, sortableScriptEngineFactory.getEngineVersion()); + } + + @Test + public void getExtensions() { + List<String> answer = Collections.emptyList(); + ScriptEngineFactory scriptEngineFactory = mock(ScriptEngineFactory.class); + when(scriptEngineFactory.getExtensions()).thenReturn(answer); + SortableScriptEngineFactory sortableScriptEngineFactory = new SortableScriptEngineFactory(scriptEngineFactory, 0, 0); + assertEquals(answer, sortableScriptEngineFactory.getExtensions()); + } + + @Test + public void getMimeTypes() { + List<String> answer = Collections.emptyList(); + ScriptEngineFactory scriptEngineFactory = mock(ScriptEngineFactory.class); + when(scriptEngineFactory.getMimeTypes()).thenReturn(answer); + SortableScriptEngineFactory sortableScriptEngineFactory = new SortableScriptEngineFactory(scriptEngineFactory, 0, 0); + assertEquals(answer, sortableScriptEngineFactory.getMimeTypes()); + } + + @Test + public void getNames() { + List<String> answer = Collections.emptyList(); + ScriptEngineFactory scriptEngineFactory = mock(ScriptEngineFactory.class); + when(scriptEngineFactory.getNames()).thenReturn(answer); + SortableScriptEngineFactory sortableScriptEngineFactory = new SortableScriptEngineFactory(scriptEngineFactory, 0, 0); + assertEquals(answer, sortableScriptEngineFactory.getNames()); + } + + @Test + public void getLanguageName() { + String answer = "answer"; + ScriptEngineFactory scriptEngineFactory = mock(ScriptEngineFactory.class); + when(scriptEngineFactory.getLanguageName()).thenReturn(answer); + SortableScriptEngineFactory sortableScriptEngineFactory = new SortableScriptEngineFactory(scriptEngineFactory, 0, 0); + assertEquals(answer, sortableScriptEngineFactory.getLanguageName()); + } + + @Test + public void getLanguageVersion() { + String answer = "answer"; + ScriptEngineFactory scriptEngineFactory = mock(ScriptEngineFactory.class); + when(scriptEngineFactory.getLanguageVersion()).thenReturn(answer); + SortableScriptEngineFactory sortableScriptEngineFactory = new SortableScriptEngineFactory(scriptEngineFactory, 0, 0); + assertEquals(answer, sortableScriptEngineFactory.getLanguageVersion()); + } + + @Test + public void getParameter() { + String answer = "answer"; + String key = "key"; + ScriptEngineFactory scriptEngineFactory = mock(ScriptEngineFactory.class); + when(scriptEngineFactory.getParameter(key)).thenReturn(answer); + SortableScriptEngineFactory sortableScriptEngineFactory = new SortableScriptEngineFactory(scriptEngineFactory, 0, 0); + assertEquals(answer, sortableScriptEngineFactory.getParameter(key)); + } + + @Test + public void getMethodCallSyntax() { + String answer = "answer"; + String obj = "obj"; + String m = "m"; + String[] args = new String[0]; + ScriptEngineFactory scriptEngineFactory = mock(ScriptEngineFactory.class); + when(scriptEngineFactory.getMethodCallSyntax(obj, m, args)).thenReturn(answer); + SortableScriptEngineFactory sortableScriptEngineFactory = new SortableScriptEngineFactory(scriptEngineFactory, 0, 0); + assertEquals(answer, sortableScriptEngineFactory.getMethodCallSyntax(obj, m, args)); + } + + @Test + public void getOutputStatement() { + String answer = "answer"; + String toDisplay = "toDisplay"; + ScriptEngineFactory scriptEngineFactory = mock(ScriptEngineFactory.class); + when(scriptEngineFactory.getOutputStatement(toDisplay)).thenReturn(answer); + SortableScriptEngineFactory sortableScriptEngineFactory = new SortableScriptEngineFactory(scriptEngineFactory, 0, 0); + assertEquals(answer, sortableScriptEngineFactory.getOutputStatement(toDisplay)); + } + + @Test + public void getProgram() { + String answer = "answer"; + String[] statements = new String[0]; + ScriptEngineFactory scriptEngineFactory = mock(ScriptEngineFactory.class); + when(scriptEngineFactory.getProgram(statements)).thenReturn(answer); + SortableScriptEngineFactory sortableScriptEngineFactory = new SortableScriptEngineFactory(scriptEngineFactory, 0, 0); + assertEquals(answer, sortableScriptEngineFactory.getProgram(statements)); + } + + @Test + public void getScriptEngine() { + ScriptEngine scriptEngine = mock(ScriptEngine.class); + ScriptEngineFactory scriptEngineFactory = mock(ScriptEngineFactory.class); + when(scriptEngineFactory.getScriptEngine()).thenReturn(scriptEngine); + SortableScriptEngineFactory sortableScriptEngineFactory = new SortableScriptEngineFactory(scriptEngineFactory, 0, 0); + assertEquals(scriptEngine, sortableScriptEngineFactory.getScriptEngine()); + } + + @Test + public void compareTo() { + SortableScriptEngineFactory same = getCompareFactory(1, 2); + assertEquals(0, same.compareTo(same)); + assertEquals(0, getCompareFactory(0, 0).compareTo(getCompareFactory(0, 0))); + assertEquals(1, getCompareFactory(1, 0).compareTo(getCompareFactory(0, 0))); + assertEquals(1, getCompareFactory(0, 1).compareTo(getCompareFactory(0, 0))); + assertEquals(1, getCompareFactory(1, 1).compareTo(getCompareFactory(1, 0))); + assertEquals(1, getCompareFactory(1, 1).compareTo(getCompareFactory(0, 1))); + assertEquals(-1, getCompareFactory(0, 0).compareTo(getCompareFactory(1, 0))); + assertEquals(-1, getCompareFactory(0, 0).compareTo(getCompareFactory(0, 1))); + assertEquals(-1, getCompareFactory(0, 1).compareTo(getCompareFactory(1, 1))); + assertEquals(-1, getCompareFactory(0, 0).compareTo(getCompareFactory(0, 1))); + } + + private SortableScriptEngineFactory getCompareFactory(long bundleId, int serviceRanking) { + return new SortableScriptEngineFactory(null, bundleId, serviceRanking); + } +} diff --git a/src/test/java/org/apache/sling/scripting/core/it/ScriptingCoreTestSupport.java b/src/test/java/org/apache/sling/scripting/core/it/ScriptingCoreTestSupport.java index a5b90da..7f35c79 100644 --- a/src/test/java/org/apache/sling/scripting/core/it/ScriptingCoreTestSupport.java +++ b/src/test/java/org/apache/sling/scripting/core/it/ScriptingCoreTestSupport.java @@ -18,6 +18,8 @@ */ package org.apache.sling.scripting.core.it; +import java.util.Arrays; + import org.apache.sling.testing.paxexam.TestSupport; import org.ops4j.pax.exam.Configuration; import org.ops4j.pax.exam.Option; @@ -28,6 +30,7 @@ import static org.apache.sling.testing.paxexam.SlingOptions.webconsole; import static org.ops4j.pax.exam.CoreOptions.composite; import static org.ops4j.pax.exam.CoreOptions.junitBundles; import static org.ops4j.pax.exam.CoreOptions.mavenBundle; +import static org.ops4j.pax.exam.CoreOptions.vmOption; import static org.ops4j.pax.exam.cm.ConfigurationAdminOptions.factoryConfiguration; import static org.ops4j.pax.exam.cm.ConfigurationAdminOptions.newConfiguration; @@ -35,7 +38,7 @@ public class ScriptingCoreTestSupport extends TestSupport { @Configuration public Option[] configuration() { - return new Option[]{ + Option[] configuration = new Option[]{ baseConfiguration(), launchpad(), // Sling Scripting Core @@ -52,6 +55,17 @@ public class ScriptingCoreTestSupport extends TestSupport { // testing junitBundles() }; + try { + Integer javaVersion = Integer.parseInt(System.getProperty("java.specification.version")); + if (javaVersion >= 9) { + Option[] java9AndBeyondConfiguration = Arrays.copyOf(configuration, configuration.length + 1); + java9AndBeyondConfiguration[java9AndBeyondConfiguration.length - 1] = vmOption("--add-modules=java.se.ee"); + configuration = java9AndBeyondConfiguration; + } + } catch (NumberFormatException e) { + // ignore + } + return configuration; } protected Option launchpad() { -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
