Author: bdelacretaz
Date: Fri Sep 6 12:57:27 2013
New Revision: 1520565
URL: http://svn.apache.org/r1520565
Log:
SLING-3038 - take context service property into account for
BindingsValuesProvider services
Added:
sling/trunk/bundles/scripting/api/src/main/java/org/apache/sling/scripting/api/BindingsValuesProvidersByContext.java
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/BindingsValuesProvidersByContextImpl.java
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/ContextBvpCollector.java
sling/trunk/bundles/scripting/core/src/test/java/org/apache/sling/scripting/core/impl/BindingsValuesProvidersByContextIT.java
Removed:
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/BindingsValuesProviderCustomizer.java
Modified:
sling/trunk/bundles/scripting/api/pom.xml
sling/trunk/bundles/scripting/core/pom.xml
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/SlingScriptAdapterFactory.java
Modified: sling/trunk/bundles/scripting/api/pom.xml
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/api/pom.xml?rev=1520565&r1=1520564&r2=1520565&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/api/pom.xml (original)
+++ sling/trunk/bundles/scripting/api/pom.xml Fri Sep 6 12:57:27 2013
@@ -63,7 +63,7 @@
javax.script
</Import-Package>
<Export-Package>
- org.apache.sling.scripting.api;version=2.1.0
+ org.apache.sling.scripting.api;version=2.2.0
</Export-Package>
</instructions>
</configuration>
Added:
sling/trunk/bundles/scripting/api/src/main/java/org/apache/sling/scripting/api/BindingsValuesProvidersByContext.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/api/src/main/java/org/apache/sling/scripting/api/BindingsValuesProvidersByContext.java?rev=1520565&view=auto
==============================================================================
---
sling/trunk/bundles/scripting/api/src/main/java/org/apache/sling/scripting/api/BindingsValuesProvidersByContext.java
(added)
+++
sling/trunk/bundles/scripting/api/src/main/java/org/apache/sling/scripting/api/BindingsValuesProvidersByContext.java
Fri Sep 6 12:57:27 2013
@@ -0,0 +1,58 @@
+/*
+ * 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.api;
+
+import java.util.Collection;
+
+import javax.script.ScriptEngineFactory;
+
+import org.apache.sling.scripting.api.BindingsValuesProvider;
+
+/** Provides {@link BindingsValuesProvider} for specific contexts, based on
+ * their "context" service property.
+ * */
+public interface BindingsValuesProvidersByContext {
+
+ /** The name of the multi-value service property that defines the
context(s) to which
+ * a BindingsValuesProvider applies.
+ */
+ String CONTEXT = "context";
+
+ /** The default value of the CONTEXT service property, used for
compatibility with
+ * previous versions of this bundle that didn't require it.
+ */
+ String DEFAULT_CONTEXT = "request";
+
+ /** Retrieve the current {@link BindingsValuesProvider} for
+ * the supplied ScriptEngineFactory and context.
+ *
+ * @param scriptEngineFactory metadata of the ScriptEngine that's being
used
+ * @param context Only BindingsValuesProviders that have this value in
their CONTEXT
+ * service property are considered. For backwards compatibility,
BindingsValuesProviders
+ * which do not have a CONTEXT service property are considered to
have CONTEXT=request.
+ * @return The returned Collection of BindingsValuesProvider is sorted
+ * so as to give preference to more specific
BindingsValuesProvider
+ * over those that match a compatible.javax.script.name
ScriptEngineFactory property,
+ * for example, in the same way that the
SlingScriptAdapterFactory did before
+ * this service was implemented.
+ */
+ Collection<BindingsValuesProvider> getBindingsValuesProviders(
+ ScriptEngineFactory scriptEngineFactory,
+ String context);
+}
Modified: sling/trunk/bundles/scripting/core/pom.xml
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/core/pom.xml?rev=1520565&r1=1520564&r2=1520565&view=diff
==============================================================================
--- sling/trunk/bundles/scripting/core/pom.xml (original)
+++ sling/trunk/bundles/scripting/core/pom.xml Fri Sep 6 12:57:27 2013
@@ -36,6 +36,13 @@
Sling Scripting core functionality
</description>
+ <properties>
+ <exam.version>3.0.3</exam.version>
+ <url.version>1.5.2</url.version>
+
<bundle.file.name>${basedir}/target/${project.build.finalName}.jar</bundle.file.name>
+ <sling.java.version>6</sling.java.version>
+ </properties>
+
<scm>
<connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/bundles/scripting/core</connection>
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/bundles/scripting/core</developerConnection>
@@ -67,6 +74,25 @@
</instructions>
</configuration>
</plugin>
+ <plugin>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <systemProperties>
+ <property>
+ <name>bundle.file.name</name>
+ <value>${bundle.file.name}</value>
+ </property>
+ </systemProperties>
+ </configuration>
+ </plugin>
</plugins>
</build>
<reporting>
@@ -110,17 +136,21 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.scripting.api</artifactId>
- <version>2.1.4</version>
+ <version>2.1.5-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
+ <version>4.2.0</version>
+ <scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
+ <version>4.2.0</version>
+ <scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
@@ -155,5 +185,39 @@
<version>2.0.6</version>
<scope>test</scope>
</dependency>
- </dependencies>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-native</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit4</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-link-mvn</artifactId>
+ <version>${exam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-aether</artifactId>
+ <version>${url.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>3.2.2</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
</project>
Added:
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/BindingsValuesProvidersByContextImpl.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/BindingsValuesProvidersByContextImpl.java?rev=1520565&view=auto
==============================================================================
---
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/BindingsValuesProvidersByContextImpl.java
(added)
+++
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/BindingsValuesProvidersByContextImpl.java
Fri Sep 6 12:57:27 2013
@@ -0,0 +1,193 @@
+/*
+ * 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.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.script.ScriptEngineFactory;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+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.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Our default {@link BindingsValuesProvidersByContext} implementation */
+@Component
+@Service
+public class BindingsValuesProvidersByContextImpl implements
BindingsValuesProvidersByContext, ServiceTrackerCustomizer {
+
+ private final Map<String, ContextBvpCollector> customizers = new
HashMap<String, ContextBvpCollector>();
+ public static final String [] DEFAULT_CONTEXT_ARRAY = new String [] {
DEFAULT_CONTEXT };
+
+ private ServiceTracker bvpTracker;
+ private ServiceTracker mapsTracker;
+ private BundleContext bundleContext;
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+ private final List<ServiceReference> pendingRefs = new
ArrayList<ServiceReference>();
+
+ @Reference
+ private SlingScriptEngineManager scriptEngineManager;
+
+ private abstract class ContextLoop {
+ Object apply(ServiceReference ref) {
+ final Object service = bundleContext.getService(ref);
+ if(service != null) {
+ for(String context : getContexts(ref)) {
+ ContextBvpCollector c = customizers.get(context);
+ if(c == null) {
+ synchronized
(BindingsValuesProvidersByContextImpl.this) {
+ c = new ContextBvpCollector(bundleContext);
+ customizers.put(context, c);
+ }
+ }
+ applyInContext(c);
+ }
+ }
+ return service;
+ }
+
+ protected abstract void applyInContext(ContextBvpCollector c);
+ };
+
+ @Activate
+ public void activate(ComponentContext ctx) {
+ bundleContext = ctx.getBundleContext();
+
+ synchronized (pendingRefs) {
+ for(ServiceReference ref : pendingRefs) {
+ addingService(ref);
+ }
+ pendingRefs.clear();
+ }
+
+ bvpTracker = new ServiceTracker(bundleContext,
BindingsValuesProvider.class.getName(), this);
+ bvpTracker.open();
+
+ // Map services can also be registered to provide bindings
+ mapsTracker = new ServiceTracker(bundleContext, Map.class.getName(),
this);
+ mapsTracker.open();
+ }
+
+ @Deactivate
+ public void deactivate(ComponentContext ctx) {
+ bvpTracker.close();
+ mapsTracker.close();
+ bundleContext = null;
+ }
+
+ public Collection<BindingsValuesProvider> getBindingsValuesProviders(
+ ScriptEngineFactory scriptEngineFactory,
+ String context) {
+ final List<BindingsValuesProvider> results = new
ArrayList<BindingsValuesProvider>();
+ if(context == null) {
+ context = DEFAULT_CONTEXT;
+ }
+ final ContextBvpCollector bvpc = customizers.get(context);
+ if(bvpc == null) {
+ logger.debug("no BindingsValuesProviderCustomizer available for
context '{}'", context);
+ return results;
+ }
+
+ results.addAll(bvpc.getGenericBindingsValuesProviders().values());
+ logger.debug("Generic BindingsValuesProviders added for engine {}:
{}", scriptEngineFactory.getNames(), results);
+
+ // we load the compatible language ones first so that the most specific
+ // overrides these
+ Map<Object, 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) {
+ final Map<Object, BindingsValuesProvider> langProviders =
bvpc.getLangBindingsValuesProviders().get(name);
+ if (langProviders != null) {
+ results.addAll(langProviders.values());
+ }
+ }
+ logger.debug("Compatible BindingsValuesProviders added for engine
{}: {}", scriptEngineFactory.getNames(), results);
+ }
+
+ for (final String name : scriptEngineFactory.getNames()) {
+ final Map<Object, BindingsValuesProvider> langProviders =
bvpc.getLangBindingsValuesProviders().get(name);
+ if (langProviders != null) {
+ results.addAll(langProviders.values());
+ }
+ }
+ logger.debug("All BindingsValuesProviders added for engine {}: {}",
scriptEngineFactory.getNames(), results);
+
+ return results;
+ }
+
+ private String [] getContexts(ServiceReference reference) {
+ return PropertiesUtil.toStringArray(reference.getProperty(CONTEXT),
new String[] { DEFAULT_CONTEXT });
+ }
+
+ public Object addingService(final ServiceReference reference) {
+ if(bundleContext == null) {
+ synchronized (pendingRefs) {
+ pendingRefs.add(reference);
+ }
+ return null;
+ }
+ return new ContextLoop() {
+ @Override
+ protected void applyInContext(ContextBvpCollector c) {
+ c.addingService(reference);
+ }
+ }.apply(reference);
+ }
+
+ public void modifiedService(final ServiceReference reference, final Object
service) {
+ new ContextLoop() {
+ @Override
+ protected void applyInContext(ContextBvpCollector c) {
+ c.modifiedService(reference, service);
+ }
+ }.apply(reference);
+ }
+
+ public void removedService(final ServiceReference reference, final Object
service) {
+ if(bundleContext == null) {
+ synchronized (pendingRefs) {
+ pendingRefs.remove(reference);
+ }
+ return;
+ }
+ new ContextLoop() {
+ @Override
+ protected void applyInContext(ContextBvpCollector c) {
+ c.removedService(reference, service);
+ }
+ }.apply(reference);
+ }
+}
Added:
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/ContextBvpCollector.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/ContextBvpCollector.java?rev=1520565&view=auto
==============================================================================
---
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/ContextBvpCollector.java
(added)
+++
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/ContextBvpCollector.java
Fri Sep 6 12:57:27 2013
@@ -0,0 +1,130 @@
+/*
+ * 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.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.script.Bindings;
+import javax.script.ScriptEngine;
+
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.scripting.api.BindingsValuesProvider;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/** Keeps track of {@link BindingsValuesProvider} for a single context */
+class ContextBvpCollector {
+
+ /** list of service property values which indicate 'any' script engine */
+ private static final List<String> ANY_ENGINE = Arrays.asList("*", "ANY");
+
+ private final BundleContext bundleContext;
+
+ /**
+ * The BindingsValuesProvider impls which apply to all languages. Keys are
serviceIds.
+ */
+ private final Map<Object, BindingsValuesProvider>
genericBindingsValuesProviders;
+
+ /**
+ * The BindingsValuesProvider impls which apply to a specific language.
+ */
+ private final Map<String, Map<Object, BindingsValuesProvider>>
langBindingsValuesProviders;
+
+ ContextBvpCollector(BundleContext bc) {
+ bundleContext = bc;
+ genericBindingsValuesProviders = new ConcurrentHashMap<Object,
BindingsValuesProvider>();
+ langBindingsValuesProviders = new ConcurrentHashMap<String,
Map<Object, BindingsValuesProvider>>();
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object addingService(final ServiceReference ref) {
+ final String[] engineNames = PropertiesUtil
+ .toStringArray(ref.getProperty(ScriptEngine.NAME), new
String[0]);
+ final Object serviceId = ref.getProperty(Constants.SERVICE_ID);
+ Object service = bundleContext.getService(ref);
+ if (service != null) {
+ if (service instanceof Map) {
+ service = new MapWrappingBindingsValuesProvider((Map<String,
Object>) service);
+ }
+ if (engineNames.length == 0) {
+ genericBindingsValuesProviders.put(serviceId,
(BindingsValuesProvider) service);
+ } else if (engineNames.length == 1 &&
ANY_ENGINE.contains(engineNames[0].toUpperCase())) {
+ genericBindingsValuesProviders.put(serviceId,
(BindingsValuesProvider) service);
+ } else {
+ for (String engineName : engineNames) {
+ Map<Object, BindingsValuesProvider> langProviders =
langBindingsValuesProviders.get(engineName);
+ if (langProviders == null) {
+ langProviders = new ConcurrentHashMap<Object,
BindingsValuesProvider>();
+ langBindingsValuesProviders.put(engineName,
langProviders);
+ }
+
+ langProviders.put(serviceId, (BindingsValuesProvider)
service);
+ }
+ }
+ }
+ return service;
+ }
+
+ public void modifiedService(final ServiceReference ref, final Object
service) {
+ removedService(ref, service);
+ addingService(ref);
+ }
+
+ public void removedService(final ServiceReference ref, final Object
service) {
+ Object serviceId = ref.getProperty(Constants.SERVICE_ID);
+ if (genericBindingsValuesProviders.remove(serviceId) == null) {
+ for (Map<Object, BindingsValuesProvider> coll :
langBindingsValuesProviders.values()) {
+ if (coll.remove(service) != null) {
+ return;
+ }
+ }
+ }
+ }
+
+ Map<Object, BindingsValuesProvider> getGenericBindingsValuesProviders() {
+ return genericBindingsValuesProviders;
+ }
+
+ Map<String, Map<Object, BindingsValuesProvider>>
getLangBindingsValuesProviders() {
+ return langBindingsValuesProviders;
+ }
+
+ private class MapWrappingBindingsValuesProvider implements
BindingsValuesProvider {
+
+ private Map<String,Object> map;
+
+ MapWrappingBindingsValuesProvider(Map<String, Object> map) {
+ this.map = map;
+ }
+
+ public void addBindings(Bindings bindings) {
+ for (String key : map.keySet()) {
+ bindings.put(key, map.get(key));
+ }
+ }
+
+ @Override
+ public String toString() {
+ return map.toString();
+ }
+ }
+
+}
\ No newline at end of file
Modified:
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/SlingScriptAdapterFactory.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/SlingScriptAdapterFactory.java?rev=1520565&r1=1520564&r2=1520565&view=diff
==============================================================================
---
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/SlingScriptAdapterFactory.java
(original)
+++
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/SlingScriptAdapterFactory.java
Fri Sep 6 12:57:27 2013
@@ -16,13 +16,10 @@
*/
package org.apache.sling.scripting.core.impl;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-import java.util.Map;
import javax.script.ScriptEngine;
-import javax.script.ScriptEngineFactory;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
@@ -32,16 +29,11 @@ import org.apache.felix.scr.annotations.
import org.apache.sling.api.adapter.AdapterFactory;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.commons.mime.MimeTypeProvider;
-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.osgi.framework.BundleContext;
-import org.osgi.framework.Filter;
-import org.osgi.framework.InvalidSyntaxException;
import org.osgi.service.component.ComponentContext;
-import org.osgi.util.tracker.ServiceTracker;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* AdapterFactory that adapts Resources to the DefaultSlingScript servlet,
which
@@ -59,19 +51,10 @@ import org.slf4j.LoggerFactory;
})
public class SlingScriptAdapterFactory implements AdapterFactory,
MimeTypeProvider {
- private final Logger log =
LoggerFactory.getLogger(SlingScriptAdapterFactory.class);
-
private BundleContext bundleContext;
- /**
- * The service tracker for BindingsValuesProvider impls
- */
- private ServiceTracker bindingsValuesProviderTracker;
-
- /**
- * The service tracker for Map impls with scripting bindings
- */
- private ServiceTracker mapBindingsValuesProviderTracker;
+ /** The context string to use to select BindingsValuesProviders */
+ public static final String BINDINGS_CONTEXT =
BindingsValuesProvidersByContext.DEFAULT_CONTEXT;
/**
* The service cache for script execution.
@@ -85,9 +68,10 @@ public class SlingScriptAdapterFactory i
private SlingScriptEngineManager scriptEngineManager;
/**
- * The customizer for BindingsValuesProvider service trackers
+ * The BindingsValuesProviderTracker
*/
- private BindingsValuesProviderCustomizer bindingsValuesProviderCustomizer;
+ @Reference
+ private BindingsValuesProvidersByContext bindingsValuesProviderTracker;
// ---------- AdapterFactory
-----------------------------------------------
@@ -100,7 +84,8 @@ public class SlingScriptAdapterFactory i
ScriptEngine engine = scriptEngineManager.getEngineByExtension(ext);
if (engine != null) {
- Collection<BindingsValuesProvider> bindingsValuesProviders =
getBindingsValuesProviders(engine.getFactory());
+ final Collection<BindingsValuesProvider> bindingsValuesProviders =
+
bindingsValuesProviderTracker.getBindingsValuesProviders(engine.getFactory(),
BINDINGS_CONTEXT);
// unchecked cast
return (AdapterType) new DefaultSlingScript(this.bundleContext,
resource, engine, bindingsValuesProviders,
this.serviceCache);
@@ -161,62 +146,12 @@ public class SlingScriptAdapterFactory i
protected void activate(ComponentContext context) {
bundleContext = context.getBundleContext();
- bindingsValuesProviderCustomizer = new
BindingsValuesProviderCustomizer(bundleContext);
-
- this.bindingsValuesProviderTracker = new
ServiceTracker(this.bundleContext, BindingsValuesProvider.class.getName(),
bindingsValuesProviderCustomizer);
- this.bindingsValuesProviderTracker.open();
-
- try {
- Filter filter =
this.bundleContext.createFilter(String.format("(&(objectclass=%s)(javax.script.name=*))",
- Map.class.getName()));
-
- this.mapBindingsValuesProviderTracker = new
ServiceTracker(this.bundleContext, filter, bindingsValuesProviderCustomizer);
- this.mapBindingsValuesProviderTracker.open();
- } catch (InvalidSyntaxException e) {
- log.warn("Unable to create ServiceTracker for Map-based script
bindiings", e);
- }
this.serviceCache = new ServiceCache(this.bundleContext);
}
protected void deactivate(ComponentContext context) {
this.serviceCache.dispose();
this.serviceCache = null;
-
- if (this.bindingsValuesProviderTracker != null) {
- this.bindingsValuesProviderTracker.close();
- this.bindingsValuesProviderTracker = null;
- }
- if (this.mapBindingsValuesProviderTracker != null) {
- this.mapBindingsValuesProviderTracker.close();
- this.mapBindingsValuesProviderTracker = null;
- }
this.bundleContext = null;
}
-
- private Collection<BindingsValuesProvider>
getBindingsValuesProviders(ScriptEngineFactory scriptEngineFactory) {
- final List<BindingsValuesProvider> results = new
ArrayList<BindingsValuesProvider>();
-
results.addAll(bindingsValuesProviderCustomizer.getGenericBindingsValuesProviders().values());
-
- // we load the compatible language ones first so that the most specific
- // overrides these
- Map<Object, 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) {
- final Map<Object, BindingsValuesProvider> langProviders =
bindingsValuesProviderCustomizer.getLangBindingsValuesProviders().get(name);
- if (langProviders != null) {
- results.addAll(langProviders.values());
- }
- }
- }
-
- for (final String name : scriptEngineFactory.getNames()) {
- final Map<Object, BindingsValuesProvider> langProviders =
bindingsValuesProviderCustomizer.getLangBindingsValuesProviders().get(name);
- if (langProviders != null) {
- results.addAll(langProviders.values());
- }
- }
-
- return results;
- }
}
Added:
sling/trunk/bundles/scripting/core/src/test/java/org/apache/sling/scripting/core/impl/BindingsValuesProvidersByContextIT.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/core/src/test/java/org/apache/sling/scripting/core/impl/BindingsValuesProvidersByContextIT.java?rev=1520565&view=auto
==============================================================================
---
sling/trunk/bundles/scripting/core/src/test/java/org/apache/sling/scripting/core/impl/BindingsValuesProvidersByContextIT.java
(added)
+++
sling/trunk/bundles/scripting/core/src/test/java/org/apache/sling/scripting/core/impl/BindingsValuesProvidersByContextIT.java
Fri Sep 6 12:57:27 2013
@@ -0,0 +1,256 @@
+/*
+ * 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.assertEquals;
+import static org.ops4j.pax.exam.CoreOptions.bundle;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import static org.ops4j.pax.exam.CoreOptions.when;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.script.Bindings;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+
+import org.apache.sling.scripting.api.BindingsValuesProvider;
+import org.apache.sling.scripting.api.BindingsValuesProvidersByContext;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+@RunWith(PaxExam.class)
+public class BindingsValuesProvidersByContextIT {
+
+ @Inject
+ private BindingsValuesProvidersByContext bvpProvider;
+
+ @Inject
+ private BundleContext bundleContext;
+
+ private final List<ServiceRegistration> regs = new
ArrayList<ServiceRegistration>();
+
+ @org.ops4j.pax.exam.Configuration
+ public Option[] config() {
+ final String localRepo = System.getProperty("maven.repo.local", "");
+
+ final String bundleFileName = System.getProperty( "bundle.file.name",
"BUNDLE_FILE_NOT_SET" );
+ final File bundleFile = new File( bundleFileName );
+ if(!bundleFile.canRead()) {
+ throw new IllegalArgumentException( "Cannot read from bundle file
" + bundleFile.getAbsolutePath());
+ }
+
+ return options(
+ when( localRepo.length() > 0 ).useOptions(
+
systemProperty("org.ops4j.pax.url.mvn.localRepository").value(localRepo)
+ ),
+ provision(
+ bundle(bundleFile.toURI().toString()),
+ mavenBundle("org.apache.felix",
"org.apache.felix.scr", "1.6.2"),
+
+ mavenBundle("org.apache.sling",
"org.apache.sling.scripting.api", "2.1.5-SNAPSHOT"),
+ mavenBundle("org.apache.sling",
"org.apache.sling.api", "2.4.2"),
+ mavenBundle("org.apache.sling",
"org.apache.sling.commons.mime", "2.1.4"),
+ mavenBundle("org.apache.sling",
"org.apache.sling.commons.osgi", "2.2.0"),
+
+ mavenBundle("org.mortbay.jetty", "servlet-api-2.5",
"6.1.14")
+ ),
+ junitBundles()
+ );
+ }
+
+ @Before
+ public void setup() {
+ regs.clear();
+ }
+
+ @After
+ public void cleanup() {
+ for(ServiceRegistration reg : regs) {
+ reg.unregister();
+ }
+ }
+
+
+ private Dictionary<String, Object> getProperties(String context, String
engineName) {
+ final Dictionary<String, Object> props = new Hashtable<String,
Object>();
+ if(context != null) {
+ props.put(BindingsValuesProvidersByContext.CONTEXT,
context.split(","));
+ }
+ if(engineName != null) {
+ props.put(ScriptEngine.NAME, engineName);
+ }
+ return props;
+ }
+
+ private void addBVP(final String id, String context, String engineName) {
+ final BindingsValuesProvider bvp = new BindingsValuesProvider() {
+ @Override
+ public String toString() {
+ return id;
+ }
+
+ public void addBindings(Bindings b) {
+ }
+ };
+
+
regs.add(bundleContext.registerService(BindingsValuesProvider.class.getName(),
bvp, getProperties(context, engineName)));
+ }
+
+ private void addMap(final String id, String context, String engineName) {
+ final Map<String, Object> result = new HashMap<String, Object>() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public String toString() {
+ return "M_" + id;
+ }
+ };
+
+ regs.add(bundleContext.registerService(Map.class.getName(), result,
getProperties(context, engineName)));
+ }
+
+ private ScriptEngineFactory factory(final String engineName) {
+ return new ScriptEngineFactory() {
+
+ public ScriptEngine getScriptEngine() {
+ return null;
+ }
+
+ public String getProgram(String... arg0) {
+ return null;
+ }
+
+ public Object getParameter(String arg0) {
+ return null;
+ }
+
+ public String getOutputStatement(String arg0) {
+ return null;
+ }
+
+ public List<String> getNames() {
+ final List<String> names = new ArrayList<String>();
+ names.add(engineName);
+ return names;
+ }
+
+ public List<String> getMimeTypes() {
+ return null;
+ }
+
+ public String getMethodCallSyntax(String arg0, String arg1,
String... arg2) {
+ return null;
+ }
+
+ public String getLanguageVersion() {
+ return null;
+ }
+
+ public String getLanguageName() {
+ return null;
+ }
+
+ public List<String> getExtensions() {
+ return null;
+ }
+
+ public String getEngineVersion() {
+ return null;
+ }
+
+ public String getEngineName() {
+ return engineName;
+ }
+ };
+ }
+
+ private String asString(Collection<?> data) {
+ final StringBuilder sb = new StringBuilder();
+ for(Object o : data) {
+ if(sb.length() > 0) {
+ sb.append(",");
+ }
+ sb.append(o.toString());
+ }
+ return sb.toString();
+ }
+
+ @Test
+ public void testAny() {
+ addBVP("one", null, "js");
+ addBVP("two", null, null);
+ addBVP("three", null, "*");
+ addBVP("four", null, "ANY");
+ addBVP("five", null, "basic");
+
+ assertEquals("four,three,two,one",
asString(bvpProvider.getBindingsValuesProviders(factory("js"), null)));
+ assertEquals("four,three,two,five",
asString(bvpProvider.getBindingsValuesProviders(factory("basic"), null)));
+ assertEquals("four,three,two",
asString(bvpProvider.getBindingsValuesProviders(factory("other"), null)));
+ }
+
+ @Test
+ public void testContextsAndLanguages() {
+ addBVP("foo", null, "js");
+ addBVP("bar", null, null);
+ addBVP("r1", "request", "js");
+ addBVP("r2", "request", null);
+ addBVP("o1", "other", "js");
+ addBVP("o2", "other", null);
+ addBVP("o3", "other,request", null);
+ addBVP("python", "python", "python");
+ assertEquals("o3,r2,bar,r1,foo",
asString(bvpProvider.getBindingsValuesProviders(factory("js"), "request")));
+ assertEquals("With default content", "o3,r2,bar,r1,foo",
asString(bvpProvider.getBindingsValuesProviders(factory("js"), null)));
+ assertEquals("o3,o2,o1",
asString(bvpProvider.getBindingsValuesProviders(factory("js"), "other")));
+ assertEquals("",
asString(bvpProvider.getBindingsValuesProviders(factory("js"),
"unusedContext")));
+ }
+
+ @Test
+ public void testMapsAndBvps() {
+ addBVP("foo", null, "js");
+ addMap("bar", null, null);
+ addMap("r1", "request", "js");
+ addMap("r2", "request", null);
+ addMap("o1", "other", "js");
+ addBVP("o2", "other", null);
+ addMap("o3", "other,request", null);
+ addMap("python", "python", "python");
+ assertEquals("M_o3,M_r2,M_bar,M_r1,foo",
asString(bvpProvider.getBindingsValuesProviders(factory("js"), "request")));
+ assertEquals("With default content", "M_o3,M_r2,M_bar,M_r1,foo",
asString(bvpProvider.getBindingsValuesProviders(factory("js"), null)));
+ assertEquals("M_o3,o2,M_o1",
asString(bvpProvider.getBindingsValuesProviders(factory("js"), "other")));
+ assertEquals("",
asString(bvpProvider.getBindingsValuesProviders(factory("js"),
"unusedContext")));
+ }
+}
\ No newline at end of file