added script context for executing bundled scripts
diff --git a/main/java/org/apache/sling/scripting/resolver/BundledScriptFinder.java b/main/java/org/apache/sling/scripting/resolver/BundledScriptFinder.java
index 2de45bc..0b7d647 100644
--- a/main/java/org/apache/sling/scripting/resolver/BundledScriptFinder.java
+++ b/main/java/org/apache/sling/scripting/resolver/BundledScriptFinder.java
@@ -27,6 +27,16 @@
@ProviderType
public interface BundledScriptFinder {
+ /**
+ * Given a {@code request}, this method finds the most appropriate bundled script to execute, taking into account the {@code
+ * scriptExtensions} priority.
+ *
+ * @param request the request for which the script has to be found
+ * @param bundle the bundle in which the scripts for the current resource type are packed (see
+ * {@link SlingHttpServletRequest#getResource()})
+ * @return the script to execute
+ * @throws IOException if the script cannot be located
+ */
Script getScript(SlingHttpServletRequest request, Bundle bundle) throws IOException;
}
diff --git a/main/java/org/apache/sling/scripting/resolver/Script.java b/main/java/org/apache/sling/scripting/resolver/Script.java
index ab0c893..34ff3a3 100644
--- a/main/java/org/apache/sling/scripting/resolver/Script.java
+++ b/main/java/org/apache/sling/scripting/resolver/Script.java
@@ -18,21 +18,22 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package org.apache.sling.scripting.resolver;
-import java.io.Reader;
+import java.io.IOException;
+import java.net.URL;
-import javax.annotation.Nonnull;
-import javax.script.Bindings;
-import javax.script.ScriptException;
+import javax.script.ScriptEngine;
import org.osgi.annotation.versioning.ProviderType;
@ProviderType
public interface Script {
- Reader getSourceCodeReader();
+ String getSourceCode() throws IOException;
- String getSourceCode();
+ ScriptEngine getScriptEngine();
- Object eval(@Nonnull Bindings props) throws ScriptException;
+ URL getURL();
+
+ String getName();
}
diff --git a/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptContext.java b/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptContext.java
new file mode 100644
index 0000000..e6af123
--- /dev/null
+++ b/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptContext.java
@@ -0,0 +1,156 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.resolver.internal;
+
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.script.Bindings;
+import javax.script.SimpleBindings;
+import javax.script.SimpleScriptContext;
+
+import org.apache.sling.api.scripting.SlingScriptConstants;
+
+class BundledScriptContext extends SimpleScriptContext {
+
+ private static final Integer[] SCOPES = {SlingScriptConstants.SLING_SCOPE, GLOBAL_SCOPE, ENGINE_SCOPE};
+
+ private Bindings globalScope;
+ private Bindings engineScope;
+
+ private Bindings slingScope = new SimpleBindings();
+
+ @Override
+ public void setBindings(final Bindings bindings, final int scope) {
+ switch (scope) {
+ case SlingScriptConstants.SLING_SCOPE : this.slingScope = bindings;
+ break;
+ case 100: if (bindings == null) throw new NullPointerException("Bindings for ENGINE scope is null");
+ this.engineScope = bindings;
+ break;
+ case 200: this.globalScope = bindings;
+ break;
+ default: throw new IllegalArgumentException("Invalid scope");
+ }
+ }
+
+ @Override
+ public Bindings getBindings(final int scope) {
+ switch (scope) {
+ case SlingScriptConstants.SLING_SCOPE : return slingScope;
+ case 100: return this.engineScope;
+ case 200: return this.globalScope;
+ }
+ throw new IllegalArgumentException("Invalid scope");
+ }
+
+ @Override
+ public void setAttribute(final String name, final Object value, final int scope) {
+ if (name == null) throw new IllegalArgumentException("Name is null");
+ final Bindings bindings = getBindings(scope);
+ if (bindings != null) {
+ bindings.put(name, value);
+ }
+ }
+
+ @Override
+ public Object getAttribute(final String name, final int scope) {
+ if (name == null) throw new IllegalArgumentException("Name is null");
+ final Bindings bindings = getBindings(scope);
+ if (bindings != null) {
+ return bindings.get(name);
+ }
+ return null;
+ }
+
+ @Override
+ public Object removeAttribute(final String name, final int scope) {
+ if (name == null) throw new IllegalArgumentException("Name is null");
+ final Bindings bindings = getBindings(scope);
+ if (bindings != null) {
+ return bindings.remove(name);
+ }
+ return null;
+ }
+
+ @Override
+ public Object getAttribute(String name) {
+ if (name == null) throw new IllegalArgumentException("Name is null");
+ for (final int scope : SCOPES) {
+ final Bindings bindings = getBindings(scope);
+ if ( bindings != null ) {
+ final Object o = bindings.get(name);
+ if ( o != null ) {
+ return o;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public int getAttributesScope(String name) {
+ if (name == null) throw new IllegalArgumentException("Name is null");
+ for (final int scope : SCOPES) {
+ if ((getBindings(scope) != null) && (getBindings(scope).containsKey(name))) {
+ return scope;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public List<Integer> getScopes() {
+ return Arrays.asList(SCOPES);
+ }
+
+ @Override
+ public Writer getWriter() {
+ return writer;
+ }
+
+ @Override
+ public Writer getErrorWriter() {
+ return errorWriter;
+ }
+
+ @Override
+ public void setWriter(Writer writer) {
+ this.writer = writer;
+ }
+
+ @Override
+ public void setErrorWriter(Writer writer) {
+ this.errorWriter = writer;
+ }
+
+ @Override
+ public Reader getReader() {
+ return reader;
+ }
+
+ @Override
+ public void setReader(Reader reader) {
+ this.reader = reader;
+ }
+
+
+}
diff --git a/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptFinderImpl.java b/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptFinderImpl.java
index a1c1aad..b8ccb01 100644
--- a/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptFinderImpl.java
+++ b/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptFinderImpl.java
@@ -20,7 +20,6 @@
import java.io.IOException;
import java.net.URL;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -28,7 +27,6 @@
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
-import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.scripting.resolver.BundledScriptFinder;
@@ -75,8 +73,7 @@
for (String extension : scriptEngineExtensions) {
URL bundledScriptURL = bundle.getEntry(BundledScriptTracker.NS_JAVAX_SCRIPT_CAPABILITY + "/" + scriptPath + "." + extension);
if (bundledScriptURL != null) {
- return new ScriptImpl(scriptEngineManager.getEngineByExtension(extension),
- IOUtils.toString(bundledScriptURL.openStream(), StandardCharsets.UTF_8));
+ return new ScriptImpl(bundledScriptURL, scriptEngineManager.getEngineByExtension(extension));
}
}
return null;
diff --git a/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptServlet.java b/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptServlet.java
index fd7a972..de727d6 100644
--- a/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptServlet.java
+++ b/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptServlet.java
@@ -19,42 +19,61 @@
package org.apache.sling.scripting.resolver.internal;
import java.io.IOException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
+import java.net.URI;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
-import javax.script.ScriptEngineFactory;
-import javax.script.ScriptEngineManager;
-import javax.servlet.ServletException;
+import javax.script.CompiledScript;
+import javax.script.ScriptContext;
+import javax.script.ScriptException;
import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.api.SlingConstants;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.scripting.ScriptEvaluationException;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.scripting.resolver.BundledScriptFinder;
+import org.apache.sling.scripting.resolver.Script;
import org.osgi.framework.Bundle;
class BundledScriptServlet extends SlingAllMethodsServlet {
private final Bundle m_bundle;
private final BundledScriptFinder m_bundledScriptFinder;
+ private final ScriptContextProvider m_scriptContextProvider;
- BundledScriptServlet(BundledScriptFinder bundledScriptFinder, Bundle bundle) {
+ private Map<URI, CompiledScript> compiledScriptsMap = new ConcurrentHashMap<>();
+
+ BundledScriptServlet(BundledScriptFinder bundledScriptFinder, Bundle bundle, ScriptContextProvider scriptContextProvider) {
m_bundle = bundle;
m_bundledScriptFinder = bundledScriptFinder;
+ m_scriptContextProvider = scriptContextProvider;
}
@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
- String scriptSource = m_bundledScriptFinder.getScript(request, m_bundle).getSourceCode();
- if (scriptSource != null) {
- response.getWriter().append(scriptSource);
- response.setContentType("text/plain");
- response.flushBuffer();
+ Script script = m_bundledScriptFinder.getScript(request, m_bundle);
+ if (script != null) {
+ if (request.getAttribute(SlingConstants.ATTR_INCLUDE_SERVLET_PATH) == null) {
+ final String contentType = request.getResponseContentType();
+ if (contentType != null) {
+ response.setContentType(contentType);
+
+ // only set the character encoding for text/ content types
+ // see SLING-679
+ if (contentType.startsWith("text/")) {
+ response.setCharacterEncoding("UTF-8");
+ }
+ }
+ }
+ ScriptContext scriptContext = m_scriptContextProvider.prepareScriptContext(request, response, script);
+ try {
+ script.getScriptEngine().eval(script.getSourceCode(), scriptContext);
+ } catch (ScriptException e) {
+ Throwable cause = (e.getCause() == null) ? e : e.getCause();
+ throw new ScriptEvaluationException(script.getName(), e.getMessage(), cause);
+ }
} else {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
diff --git a/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptTracker.java b/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptTracker.java
index b7b2a37..ff86864 100644
--- a/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptTracker.java
+++ b/main/java/org/apache/sling/scripting/resolver/internal/BundledScriptTracker.java
@@ -56,6 +56,9 @@
@Reference
private BundledScriptFinder bundledScriptFinder;
+ @Reference
+ private ScriptContextProvider scriptContextProvider;
+
public static final String NS_JAVAX_SCRIPT_CAPABILITY = "javax.script";
public static final String AT_SLING_RESOURCE_TYPE = "sling.resourceType";
public static final String AT_SLING_RESOURCE_TYPE_VERSION = "sling.resourceType.version";
@@ -96,7 +99,7 @@
properties.put("sling.servlet.resourceTypes", resourceTypes);
properties.put("sling.servlet.methods", new String[]{"TRACE", "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE"});
LOGGER.debug("Registering bundle {} for {} resourceTypes.", bundle.getSymbolicName(), Arrays.asList(resourceTypes));
- return m_context.registerService(Servlet.class, new BundledScriptServlet(bundledScriptFinder, bundle), properties);
+ return m_context.registerService(Servlet.class, new BundledScriptServlet(bundledScriptFinder, bundle, scriptContextProvider), properties);
} else {
return null;
}
diff --git a/main/java/org/apache/sling/scripting/resolver/internal/LogWriter.java b/main/java/org/apache/sling/scripting/resolver/internal/LogWriter.java
new file mode 100644
index 0000000..aaf6925
--- /dev/null
+++ b/main/java/org/apache/sling/scripting/resolver/internal/LogWriter.java
@@ -0,0 +1,124 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.resolver.internal;
+
+import java.io.Writer;
+
+import org.slf4j.Logger;
+
+class LogWriter extends Writer {
+
+ /** The logger to which the error messages are written */
+ private Logger logger;
+
+ /**
+ * The internal buffer to gather message data until being flushed or a CR or
+ * LF is encountered in the message data.
+ */
+ private StringBuilder lineBuffer;
+
+ /**
+ * Creates a writer based on the given logger.
+ *
+ * @param logger the logger
+ */
+ public LogWriter(Logger logger) {
+ this.logger = logger;
+ this.lineBuffer = new StringBuilder();
+ }
+
+ /**
+ * Writes the character to the internal buffer unless the character is a CR
+ * or LF in which case the buffer is written to the logger as an error
+ * message.
+ */
+ @Override
+ public void write(int c) {
+ if (c == '\n' || c == '\r') {
+ flush();
+ } else {
+ synchronized (lineBuffer) {
+ lineBuffer.append((char) c);
+ }
+ }
+ }
+
+ /**
+ * Writes the indicated characters to the internal buffer, flushing the
+ * buffer on any occurrence of a CR of LF.
+ */
+ @Override
+ public void write(char[] cbuf, int off, int len) {
+ int i = off;
+ for (int n = 0; n < len; n++, i++) {
+ char c = cbuf[i];
+
+ // if CR/LF flush the line
+ if (c == '\n' || c == '\r') {
+
+ // append upto the CR/LF
+ int subLen = i - off;
+ if (subLen > 0) {
+ synchronized (lineBuffer) {
+ lineBuffer.append(cbuf, off, subLen);
+ }
+ }
+
+ // and flush
+ flush();
+
+ // new offset is after the CR/LF
+ off = i + 1;
+ }
+ }
+
+ // remaining data in the buffer is just appended
+ if (off < i) {
+ synchronized (lineBuffer) {
+ lineBuffer.append(cbuf, off, i - off);
+ }
+ }
+ }
+
+ /**
+ * Writes any data conained in the buffer to the logger as an error message.
+ */
+ @Override
+ public void flush() {
+
+ String message;
+ synchronized (lineBuffer) {
+ if (lineBuffer.length() == 0) {
+ return;
+ }
+ message = lineBuffer.toString();
+ lineBuffer.setLength(0);
+ }
+
+ logger.error(message);
+ }
+
+ /**
+ * Just calls {@link #flush()}
+ */
+ @Override
+ public void close() {
+ flush();
+ }
+}
diff --git a/main/java/org/apache/sling/scripting/resolver/internal/ProtectedBindings.java b/main/java/org/apache/sling/scripting/resolver/internal/ProtectedBindings.java
new file mode 100644
index 0000000..1f0ac33
--- /dev/null
+++ b/main/java/org/apache/sling/scripting/resolver/internal/ProtectedBindings.java
@@ -0,0 +1,145 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.resolver.internal;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import javax.script.Bindings;
+
+class ProtectedBindings implements Bindings {
+
+ private final Bindings wrapped;
+ private final Set<String> protectedKeys;
+
+ public ProtectedBindings(Bindings wrapped, Set<String> protectedKeys) {
+ this.wrapped = wrapped;
+ this.protectedKeys = protectedKeys;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws IllegalArgumentException if the key is protected
+ */
+ public Object put(String key, Object value) {
+ if (protectedKeys.contains(key)) {
+ throw new IllegalArgumentException(String.format("Key %s is protected.", key));
+ }
+ return wrapped.put(key, value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void putAll(Map<? extends String, ? extends Object> toMerge) {
+ for (Map.Entry<? extends String, ? extends Object> entry : toMerge.entrySet()) {
+ if (!protectedKeys.contains(entry.getKey())) {
+ wrapped.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws IllegalArgumentException if the key is protected
+ */
+ public Object remove(Object key) {
+ if (protectedKeys.contains(key)) {
+ throw new IllegalArgumentException(String.format("Key %s is protected.", key));
+ }
+ return wrapped.remove(key);
+ }
+
+ /**
+ * The clear operation is not supported.
+ */
+ public void clear() {
+ throw new UnsupportedOperationException("ProtectedBindings does not support clear()");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean containsValue(Object value) {
+ return wrapped.containsValue(value);
+ }
+
+ /**
+ * Returns a Set view of the mappings contains in this map. The Set is
+ * unmodifiable.
+ *
+ * @return an unmodifiable Set view of the map
+ */
+ public Set<Entry<String, Object>> entrySet() {
+ return Collections.unmodifiableSet(wrapped.entrySet());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isEmpty() {
+ return wrapped.isEmpty();
+ }
+
+ /**
+ * Returns a Set view of the keys contained in this map. The Set is
+ * unmodifiable.
+ *
+ * @return an unmodifiable Set view of the map's keys
+ */
+ public Set<String> keySet() {
+ return Collections.unmodifiableSet(wrapped.keySet());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int size() {
+ return wrapped.size();
+ }
+
+ /**
+ * Returns a Collection view of the values contained in this map. The
+ * Collection is unmodifiable.
+ *
+ * @return an unmodifiable Collection view of the map's values
+ */
+ public Collection<Object> values() {
+ return Collections.unmodifiableCollection(wrapped.values());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean containsKey(Object key) {
+ return wrapped.containsKey(key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object get(Object key) {
+ return wrapped.get(key);
+ }
+
+}
diff --git a/main/java/org/apache/sling/scripting/resolver/internal/ScriptContextProvider.java b/main/java/org/apache/sling/scripting/resolver/internal/ScriptContextProvider.java
new file mode 100644
index 0000000..cd80fa3
--- /dev/null
+++ b/main/java/org/apache/sling/scripting/resolver/internal/ScriptContextProvider.java
@@ -0,0 +1,111 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.resolver.internal;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.SimpleBindings;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.api.scripting.SlingScriptConstants;
+import org.apache.sling.scripting.api.BindingsValuesProvider;
+import org.apache.sling.scripting.api.BindingsValuesProvidersByContext;
+import org.apache.sling.scripting.api.resource.ScriptingResourceResolverProvider;
+import org.apache.sling.scripting.core.ScriptHelper;
+import org.apache.sling.scripting.resolver.Script;
+import org.osgi.framework.BundleContext;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(
+ service = ScriptContextProvider.class
+)
+public class ScriptContextProvider {
+
+ private BundleContext m_bundleContext;
+
+ private static final Set<String> PROTECTED_BINDINGS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
+ SlingBindings.REQUEST,
+ SlingBindings.RESPONSE,
+ SlingBindings.READER,
+ SlingBindings.RESOURCE,
+ SlingBindings.RESOLVER,
+ SlingBindings.OUT,
+ SlingBindings.LOG,
+ SlingBindings.SLING,
+ ScriptEngine.FILENAME
+ )));
+
+ @Reference
+ private BindingsValuesProvidersByContext bvpTracker;
+
+ @Reference
+ private ScriptingResourceResolverProvider scriptingResourceResolverProvider;
+
+ @Activate
+ private void activate(ComponentContext componentContext) {
+ m_bundleContext = componentContext.getBundleContext();
+ }
+
+ ScriptContext prepareScriptContext(SlingHttpServletRequest request, SlingHttpServletResponse response, Script script) throws IOException {
+ // prepare the SlingBindings
+ Bindings bindings = new SimpleBindings();
+ bindings.put(SlingBindings.REQUEST, request);
+ bindings.put(SlingBindings.RESPONSE, response);
+ bindings.put(SlingBindings.READER, request.getReader());
+ bindings.put(SlingBindings.RESOURCE, request.getResource());
+ bindings.put(SlingBindings.RESOLVER, request.getResource().getResourceResolver());
+ bindings.put(SlingBindings.OUT, response.getWriter());
+ Logger scriptLogger = LoggerFactory.getLogger(script.getName());
+ bindings.put(SlingBindings.LOG, scriptLogger);
+ bindings.put(SlingBindings.SLING, new ScriptHelper(m_bundleContext, null, request, response));
+ bindings.put(ScriptEngine.FILENAME, script.getName());
+
+ ProtectedBindings protectedBindings = new ProtectedBindings(bindings, PROTECTED_BINDINGS);
+ for (BindingsValuesProvider bindingsValuesProvider : bvpTracker.getBindingsValuesProviders(script.getScriptEngine().getFactory(),
+ BindingsValuesProvider.DEFAULT_CONTEXT)) {
+ bindingsValuesProvider.addBindings(protectedBindings);
+ }
+ ScriptContext scriptContext = new BundledScriptContext();
+ scriptContext.setBindings(new SimpleBindings(), SlingScriptConstants.SLING_SCOPE);
+ scriptContext.setAttribute(SlingScriptConstants.ATTR_SCRIPT_RESOURCE_RESOLVER, scriptingResourceResolverProvider
+ .getRequestScopedResourceResolver(), SlingScriptConstants.SLING_SCOPE);
+ scriptContext.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
+ scriptContext.setWriter(response.getWriter());
+ scriptContext.setErrorWriter(new LogWriter(scriptLogger));
+ scriptContext.setReader(request.getReader());
+
+ return scriptContext;
+ }
+
+
+}
diff --git a/main/java/org/apache/sling/scripting/resolver/internal/ScriptImpl.java b/main/java/org/apache/sling/scripting/resolver/internal/ScriptImpl.java
index e7b3aac..52937f0 100644
--- a/main/java/org/apache/sling/scripting/resolver/internal/ScriptImpl.java
+++ b/main/java/org/apache/sling/scripting/resolver/internal/ScriptImpl.java
@@ -18,39 +18,46 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package org.apache.sling.scripting.resolver.internal;
-import java.io.Reader;
-import java.io.StringReader;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
-import javax.annotation.Nonnull;
-import javax.script.Bindings;
import javax.script.ScriptEngine;
-import javax.script.ScriptException;
+import org.apache.commons.io.IOUtils;
import org.apache.sling.scripting.resolver.Script;
-
public class ScriptImpl implements Script {
+ private URL url;
private ScriptEngine scriptEngine;
private String sourceCode;
- public ScriptImpl(ScriptEngine scriptEngine, String sourceCode) {
+ public ScriptImpl(URL url, ScriptEngine scriptEngine) {
+ this.url = url;
this.scriptEngine = scriptEngine;
- this.sourceCode = sourceCode;
}
@Override
- public Reader getSourceCodeReader() {
- return new StringReader(sourceCode);
- }
-
- @Override
- public String getSourceCode() {
+ public String getSourceCode() throws IOException {
+ if (sourceCode == null) {
+ sourceCode = IOUtils.toString(url.openStream(), StandardCharsets.UTF_8);
+ }
return sourceCode;
}
@Override
- public Object eval(@Nonnull Bindings props) throws ScriptException {
- return scriptEngine.eval(sourceCode, props);
+ public ScriptEngine getScriptEngine() {
+ return scriptEngine;
+ }
+
+ @Override
+ public URL getURL() {
+ return url;
+ }
+
+ @Override
+ public String getName() {
+ return url.getPath();
}
}
diff --git a/test/resources/findbugs-exclude.xml b/test/resources/findbugs-exclude.xml
new file mode 100644
index 0000000..24ab733
--- /dev/null
+++ b/test/resources/findbugs-exclude.xml
@@ -0,0 +1,23 @@
+<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
+<FindBugsFilter>
+ <Match>
+ <Bug pattern="SE_BAD_FIELD" />
+ </Match>
+</FindBugsFilter>