Author: cziegeler
Date: Wed Jan 6 08:29:26 2010
New Revision: 896348
URL: http://svn.apache.org/viewvc?rev=896348&view=rev
Log:
SLING-1267 : Get metadata of script only once, get input stream lazily
SLING-1266 : Init parameters from servlet config are not used
Modified:
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/DefaultSlingScript.java
Modified:
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/DefaultSlingScript.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/DefaultSlingScript.java?rev=896348&r1=896347&r2=896348&view=diff
==============================================================================
---
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/DefaultSlingScript.java
(original)
+++
sling/trunk/bundles/scripting/core/src/main/java/org/apache/sling/scripting/core/impl/DefaultSlingScript.java
Wed Jan 6 08:29:26 2010
@@ -78,24 +78,55 @@
// resource adapts (null if the resource does not adapt to a node
private static final String NODE = "currentNode";
+ /** The logger. */
+ private static final Logger LOGGER =
LoggerFactory.getLogger(DefaultSlingScript.class);
+
+ /** Thread local containing the resource resolver. */
private static ThreadLocal<ResourceResolver> requestResourceResolver = new
ThreadLocal<ResourceResolver>();
- private final Logger logger = LoggerFactory.getLogger(this.getClass());
+ /** The resource pointing to the script. */
+ private final Resource scriptResource;
+
+ /** The name of the script (the resource path) */
+ private final String scriptName;
- private Resource scriptResource;
+ /** The encoding of the script. */
+ private final String scriptEncoding;
- private ScriptEngine scriptEngine;
+ /** The script engine for this script. */
+ private final ScriptEngine scriptEngine;
+ /** The servlet context. */
private ServletContext servletContext;
+ /** The init parameters for this servlet. */
private Dictionary<String, String> initParameters;
+ /** The current bundle context. */
private final BundleContext bundleContext;
+ /**
+ * Constructor
+ * @param bundleContext The bundle context
+ * @param scriptResource The script resource
+ * @param scriptEngine The script engine
+ */
DefaultSlingScript(BundleContext bundleContext, Resource scriptResource,
ScriptEngine scriptEngine) {
this.scriptResource = scriptResource;
this.scriptEngine = scriptEngine;
this.bundleContext = bundleContext;
+ this.scriptName = this.scriptResource.getPath();
+ // Now know how to get the input stream, we still have to decide
+ // on the encoding of the stream's data. Primarily we assume it is
+ // UTF-8, which is a default in many places in JCR. Secondarily
+ // we try to get a jcr:encoding property besides the data property
+ // to provide a possible encoding
+ final ResourceMetadata meta =
this.scriptResource.getResourceMetadata();
+ String encoding = meta.getCharacterEncoding();
+ if (encoding == null) {
+ encoding = "UTF-8";
+ }
+ this.scriptEncoding = encoding;
}
// ---------- SlingScript interface
----------------------------------------
@@ -128,12 +159,10 @@
* @throws ScriptEvaluationException
*/
public Object call(SlingBindings props, String method, Object... args) {
- final String scriptName = scriptResource.getPath();
-
Bindings bindings = null;
Reader reader = null;
try {
- bindings = verifySlingBindings(scriptName, props);
+ bindings = verifySlingBindings(props);
final ScriptContext ctx = new SimpleScriptContext() {
@@ -190,7 +219,7 @@
try {
((Invocable)scriptEngine).invokeFunction(method,
Arrays.asList(args).toArray());
} catch (NoSuchMethodException e) {
- throw new ScriptEvaluationException(scriptName, "Method "
+ method + " not found in script.", e);
+ throw new ScriptEvaluationException(this.scriptName,
"Method " + method + " not found in script.", e);
}
}
// optionall flush the output channel
@@ -205,12 +234,12 @@
return result;
} catch (IOException ioe) {
- throw new ScriptEvaluationException(scriptName, ioe.getMessage(),
+ throw new ScriptEvaluationException(this.scriptName,
ioe.getMessage(),
ioe);
} catch (ScriptException se) {
Throwable cause = (se.getCause() == null) ? se : se.getCause();
- throw new ScriptEvaluationException(scriptName, se.getMessage(),
+ throw new ScriptEvaluationException(this.scriptName,
se.getMessage(),
cause);
} finally {
@@ -234,26 +263,31 @@
}
}
+ /**
+ * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
+ */
public void init(ServletConfig servletConfig) {
if (servletConfig != null) {
- Dictionary<String, String> params = new Hashtable<String,
String>();
+ final Dictionary<String, String> params = new Hashtable<String,
String>();
for (Enumeration<?> ne = servletConfig.getInitParameterNames();
ne.hasMoreElements();) {
String name = String.valueOf(ne.nextElement());
String value = servletConfig.getInitParameter(name);
params.put(name, value);
}
-
- servletContext = servletConfig.getServletContext();
+ this.initParameters = params;
+ this.servletContext = servletConfig.getServletContext();
}
}
+ /**
+ * @see javax.servlet.Servlet#service(javax.servlet.ServletRequest,
javax.servlet.ServletResponse)
+ */
public void service(ServletRequest req, ServletResponse res) {
-
- SlingHttpServletRequest request = (SlingHttpServletRequest) req;
+ final SlingHttpServletRequest request = (SlingHttpServletRequest) req;
try {
// prepare the properties for the script
- SlingBindings props = new SlingBindings();
+ final SlingBindings props = new SlingBindings();
props.setRequest((SlingHttpServletRequest) req);
props.setResponse((SlingHttpServletResponse) res);
@@ -268,7 +302,7 @@
res.setCharacterEncoding("UTF-8");
}
} else {
- logger.debug(
+ LOGGER.debug(
"service:No response content type defined for request {}.",
request.getRequestURI());
}
@@ -305,6 +339,9 @@
return "Script " + scriptResource.getPath();
}
+ /**
+ * @see javax.servlet.Servlet#destroy()
+ */
public void destroy() {
initParameters = null;
servletContext = null;
@@ -312,49 +349,43 @@
// ---------- ServletConfig
------------------------------------------------
+ /**
+ * @see javax.servlet.ServletConfig#getInitParameter(java.lang.String)
+ */
public String getInitParameter(String name) {
- Dictionary<String, String> params = initParameters;
+ final Dictionary<String, String> params = initParameters;
return (params != null) ? params.get(name) : null;
}
+ /**
+ * @see javax.servlet.ServletConfig#getInitParameterNames()
+ */
public Enumeration<String> getInitParameterNames() {
- Dictionary<String, String> params = initParameters;
+ final Dictionary<String, String> params = initParameters;
return (params != null) ? params.keys() : null;
}
+ /**
+ * @see javax.servlet.ServletConfig#getServletContext()
+ */
public ServletContext getServletContext() {
return servletContext;
}
+ /**
+ * @see javax.servlet.ServletConfig#getServletName()
+ */
public String getServletName() {
- return scriptResource.getPath();
+ return this.scriptName;
}
// ---------- internal
-----------------------------------------------------
private Reader getScriptReader() throws IOException {
-
- InputStream input = scriptResource.adaptTo(InputStream.class);
- if (input == null) {
- throw new IOException("Cannot get a stream to the script resource "
- + scriptResource);
- }
-
- // Now know how to get the input stream, we still have to decide
- // on the encoding of the stream's data. Primarily we assume it is
- // UTF-8, which is a default in many places in JCR. Secondarily
- // we try to get a jcr:encoding property besides the data property
- // to provide a possible encoding
- ResourceMetadata meta = scriptResource.getResourceMetadata();
- String encoding = meta.getCharacterEncoding();
- if (encoding == null) {
- encoding = "UTF-8";
- }
-
// access the value as a stream and return a buffered reader
// converting the stream data using UTF-8 encoding, which is
// the default encoding used
- return new BufferedReader(new InputStreamReader(input, encoding));
+ return new BufferedReader(new InputStreamReader(new
LazyInputStream(this.scriptResource), this.scriptEncoding));
}
private Reader getWrapperReader(final Reader scriptReader, final String
method, final Object... args) {
@@ -417,8 +448,7 @@
};
}
- private Bindings verifySlingBindings(String scriptName,
- SlingBindings slingBindings) throws IOException {
+ private Bindings verifySlingBindings(SlingBindings slingBindings) throws
IOException {
Bindings bindings = new SimpleBindings();
@@ -434,51 +464,51 @@
slingObject = new ScriptHelper(this.bundleContext, this);
}
} else if (!(slingObject instanceof SlingScriptHelper) ) {
- throw fail(scriptName, SLING, "Wrong type");
+ throw fail(SLING, "Wrong type");
}
final SlingScriptHelper sling = (SlingScriptHelper)slingObject;
bindings.put(SLING, sling);
if (request != null) {
- //throw fail(scriptName, REQUEST, "Missing or wrong type");
+ //throw fail(REQUEST, "Missing or wrong type");
SlingHttpServletResponse response = slingBindings.getResponse();
if (response == null) {
- throw fail(scriptName, RESPONSE, "Missing or wrong type");
+ throw fail(RESPONSE, "Missing or wrong type");
}
Object resourceObject = slingBindings.get(RESOURCE);
if (resourceObject != null && !(resourceObject instanceof
Resource)) {
- throw fail(scriptName, RESOURCE, "Wrong type");
+ throw fail(RESOURCE, "Wrong type");
}
Object writerObject = slingBindings.get(OUT);
if (writerObject != null && !(writerObject instanceof
PrintWriter)) {
- throw fail(scriptName, OUT, "Wrong type");
+ throw fail(OUT, "Wrong type");
}
// if there is a provided sling script helper, check arguments
if (slingBindings.get(SLING) != null) {
if (sling.getRequest() != request) {
- throw fail(scriptName, REQUEST,
+ throw fail(REQUEST,
"Not the same as request field of SlingScriptHelper");
}
if (sling.getResponse() != response) {
- throw fail(scriptName, RESPONSE,
+ throw fail(RESPONSE,
"Not the same as response field of SlingScriptHelper");
}
if (resourceObject != null
&& sling.getRequest().getResource() != resourceObject) {
- throw fail(scriptName, RESOURCE,
+ throw fail(RESOURCE,
"Not the same as resource of the SlingScriptHelper
request");
}
if (writerObject != null
&& sling.getResponse().getWriter() != writerObject) {
- throw fail(scriptName, OUT,
+ throw fail(OUT,
"Not the same as writer of the SlingScriptHelper
response");
}
}
@@ -501,7 +531,7 @@
if (logObject == null) {
logObject = LoggerFactory.getLogger(getLoggerName());
} else if (!(logObject instanceof Logger)) {
- throw fail(scriptName, LOG, "Wrong type");
+ throw fail(LOG, "Wrong type");
}
bindings.put(LOG, logObject);
@@ -515,9 +545,8 @@
return bindings;
}
- private ScriptEvaluationException fail(String scriptName,
- String variableName, String message) {
- return new ScriptEvaluationException(scriptName, variableName + ": "
+ private ScriptEvaluationException fail(String variableName, String
message) {
+ return new ScriptEvaluationException(this.scriptName, variableName +
": "
+ message);
}
@@ -543,4 +572,94 @@
}
request.getRequestProgressTracker().log("SCRIPT ERROR: {0}", message);
}
+
+ /**
+ * Input stream wrapper which acquires the underlying input stream lazily.
+ * This ensures that the input stream is only fetched from the repository
+ * if it is really used by the script engines.
+ */
+ public final static class LazyInputStream extends InputStream {
+
+ /** The script resource which is adapted to an inputm stream. */
+ private final Resource resource;
+
+ /** The input stream created on demand, null if not used */
+ private InputStream delegatee;
+
+ public LazyInputStream(final Resource resource) {
+ this.resource = resource;
+ }
+
+ /**
+ * Closes the input stream if acquired otherwise does nothing.
+ */
+ @Override
+ public void close() throws IOException {
+ if (delegatee != null) {
+ delegatee.close();
+ }
+ }
+
+ @Override
+ public int available() throws IOException {
+ return getStream().available();
+ }
+
+ @Override
+ public int read() throws IOException {
+ return getStream().read();
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return getStream().read(b);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ return getStream().read(b, off, len);
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ return getStream().skip(n);
+ }
+
+ @Override
+ public boolean markSupported() {
+ try {
+ return getStream().markSupported();
+ } catch (IOException ioe) {
+ // ignore
+ }
+ return false;
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ try {
+ getStream().mark(readlimit);
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ getStream().reset();
+ }
+
+ /** Actually retrieves the input stream from the underlying JCR Value
*/
+ private InputStream getStream() throws IOException {
+ if (delegatee == null) {
+ delegatee = this.resource.adaptTo(InputStream.class);
+ if (delegatee == null) {
+ throw new IOException("Cannot get a stream to the script
resource "
+ + this.resource);
+ }
+ }
+ return delegatee;
+ }
+
+ }
}
\ No newline at end of file