This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to annotated tag org.apache.sling.scripting.java-2.0.10 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-java.git
commit 6a67edbbb35e17d9feee8985812ecaab03f0bfce Author: Justin Edelson <[email protected]> AuthorDate: Wed Oct 5 21:35:44 2011 +0000 SLING-2237 - initial implementation of @Inject support git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/scripting/java@1179454 13f79535-47bb-0310-9956-ffa450edef68 --- pom.xml | 12 ++- .../java/impl/JavaScriptEngineFactory.java | 3 +- .../sling/scripting/java/impl/ServletWrapper.java | 119 ++++++++++++++++++--- 3 files changed, 117 insertions(+), 17 deletions(-) diff --git a/pom.xml b/pom.xml index 47b1599..26e8be1 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ <parent> <groupId>org.apache.sling</groupId> <artifactId>sling</artifactId> - <version>11</version> + <version>12</version> <relativePath>../../../parent/pom.xml</relativePath> </parent> @@ -55,8 +55,9 @@ <Private-Package> org.apache.sling.scripting.java.impl </Private-Package> - <ScriptEngine-Name>${pom.name}</ScriptEngine-Name> - <ScriptEngine-Version>${pom.version}</ScriptEngine-Version> + <ScriptEngine-Name>${project.name}</ScriptEngine-Name> + <ScriptEngine-Version>${project.version}</ScriptEngine-Version> + <Export-Package>javax.inject</Export-Package> </instructions> </configuration> </plugin> @@ -123,5 +124,10 @@ <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> + <dependency> + <groupId>javax.inject</groupId> + <artifactId>javax.inject</artifactId> + <version>1</version> + </dependency> </dependencies> </project> diff --git a/src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java b/src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java index a40fa68..3eacfdf 100644 --- a/src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java +++ b/src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java @@ -238,7 +238,8 @@ public class JavaScriptEngineFactory wrapper = new ServletWrapper(servletConfig, ioProvider, - scriptName); + scriptName, + scriptHelper); this.ioProvider.getServletCache().addWrapper(scriptName, wrapper); return wrapper; diff --git a/src/main/java/org/apache/sling/scripting/java/impl/ServletWrapper.java b/src/main/java/org/apache/sling/scripting/java/impl/ServletWrapper.java index 17471cc..45b7f17 100644 --- a/src/main/java/org/apache/sling/scripting/java/impl/ServletWrapper.java +++ b/src/main/java/org/apache/sling/scripting/java/impl/ServletWrapper.java @@ -17,8 +17,16 @@ package org.apache.sling.scripting.java.impl; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.List; +import javax.inject.Inject; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -27,6 +35,7 @@ import javax.servlet.UnavailableException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.sling.api.scripting.SlingScriptHelper; import org.apache.sling.commons.classloader.DynamicClassLoader; import org.apache.sling.commons.compiler.CompilationResult; import org.apache.sling.commons.compiler.CompilerMessage; @@ -54,10 +63,18 @@ public class ServletWrapper { /** The path to the servlet. */ private final String sourcePath; + private final SlingScriptHelper scriptHelper; + /** Flag for handling modifications. */ private volatile long lastModificationTest = 0L; - /** The compiled and instantiated servlet. */ + /** The compiled class. */ + private volatile Class<?> theServletClass; + + /** + * The compiled and instantiated servlet. This field may be null in which case a new servlet + * instance is created per request. + */ private volatile Servlet theServlet; /** Flag handling an unavailable exception. */ @@ -71,11 +88,13 @@ public class ServletWrapper { */ public ServletWrapper(final ServletConfig config, final SlingIOProvider ioProvider, - final String servletPath) { + final String servletPath, + final SlingScriptHelper scriptHelper) { this.config = config; this.ioProvider = ioProvider; this.sourcePath = servletPath; this.className = CompilerUtil.mapSourcePath(this.sourcePath).substring(1).replace('/', '.'); + this.scriptHelper = scriptHelper; } /** @@ -87,6 +106,7 @@ public class ServletWrapper { public void service(HttpServletRequest request, HttpServletResponse response) throws Exception { + Servlet servlet = null; try { if ((available > 0L) && (available < Long.MAX_VALUE)) { if (available > System.currentTimeMillis()) { @@ -116,7 +136,7 @@ public class ServletWrapper { throw compileException; } - final Servlet servlet = getServlet(); + servlet = getServlet(); // invoke the servlet if (servlet instanceof SingleThreadModel) { @@ -140,6 +160,10 @@ public class ServletWrapper { (HttpServletResponse.SC_SERVICE_UNAVAILABLE, ex.getMessage()); logger.error("Java servlet {} is unavailable.", this.sourcePath); + } finally { + if (servlet != null && theServlet == null) { + servlet.destroy(); + } } } @@ -165,10 +189,8 @@ public class ServletWrapper { * Check if the used classloader is still valid */ private boolean checkReload() { - final Servlet servlet = this.theServlet; - final Class<?> servletClass = servlet != null ? servlet.getClass() : null; - if ( servletClass != null && servletClass.getClassLoader() instanceof DynamicClassLoader ) { - return !((DynamicClassLoader)servletClass.getClassLoader()).isLive(); + if ( theServletClass != null && theServletClass.getClassLoader() instanceof DynamicClassLoader ) { + return !((DynamicClassLoader)theServletClass.getClassLoader()).isLive(); } return false; } @@ -187,12 +209,72 @@ public class ServletWrapper { } } } + + if (theServlet == null && theServletClass != null) { + final Servlet servlet = (Servlet) theServletClass.newInstance(); + servlet.init(this.config); + + injectFields(servlet); + + return servlet; + } + return theServlet; } + private void injectFields(Servlet servlet) { + for (Field field : theServletClass.getDeclaredFields()) { + if (field.isAnnotationPresent(Inject.class)) { + field.setAccessible(true); + try { + Type type = field.getGenericType(); + if (type instanceof Class) { + Class<?> injectedClass = (Class<?>) type; + if (injectedClass.isInstance(scriptHelper)) { + field.set(servlet, scriptHelper); + } else if (injectedClass.isArray()) { + Object[] services = scriptHelper.getServices(injectedClass.getComponentType(), null); + Object arr = Array.newInstance(injectedClass.getComponentType(), services.length); + for (int i = 0; i < services.length; i++) { + Array.set(arr, i, services[i]); + } + field.set(servlet, arr); + } else { + field.set(servlet, scriptHelper.getService(injectedClass)); + } + } else if (type instanceof ParameterizedType) { + ParameterizedType ptype = (ParameterizedType) type; + if (ptype.getActualTypeArguments().length != 1) { + logger.warn("Field {} of {} has more than one type parameter.", field.getName(), sourcePath); + continue; + } + Class<?> collectionType = (Class<?>) ptype.getRawType(); + if (!(collectionType.equals(Collection.class) || + collectionType.equals(List.class))) { + logger.warn("Field {} of {} was not an injectable collection type.", field.getName(), sourcePath); + continue; + } + + Class<?> serviceType = (Class<?>) ptype.getActualTypeArguments()[0]; + Object[] services = scriptHelper.getServices(serviceType, null); + field.set(servlet, Arrays.asList(services)); + } else { + logger.warn("Field {} of {} was not an injectable type.", field.getName(), sourcePath); + } + } catch (IllegalArgumentException e) { + logger.error(String.format("Unable to inject into field %s of %s.", field.getName(), sourcePath), e); + } catch (IllegalAccessException e) { + logger.error(String.format("Unable to inject into field %s of %s.", field.getName(), sourcePath), e); + } finally { + field.setAccessible(false); + } + } + } + } + /** - * Compile the servlet java class - * and instantiate the servlet + * Compile the servlet java class. If the compiled class has + * injected fields, don't create an instance of it. */ private void compile() throws Exception { @@ -209,12 +291,14 @@ public class ServletWrapper { if ( errors != null && errors.size() > 0 ) { throw CompilerException.create(errors, this.sourcePath); } - if ( result.didCompile() || this.theServlet == null ) { + if ( result.didCompile() || this.theServletClass == null ) { destroy(); - final Class<?> servletClass = result.loadCompiledClass(this.className); - final Servlet servlet = (Servlet) servletClass.newInstance(); - servlet.init(this.config); + this.theServletClass = result.loadCompiledClass(this.className); + } + if ( !hasInjectedFields(this.theServletClass) ) { + final Servlet servlet = (Servlet) theServletClass.newInstance(); + servlet.init(this.config); this.theServlet = servlet; } } catch (final Exception ex) { @@ -226,6 +310,15 @@ public class ServletWrapper { } } + private static boolean hasInjectedFields(Class<?> clazz) { + for (Field field : clazz.getDeclaredFields()) { + if (field.isAnnotationPresent(Inject.class)) { + return true; + } + } + return false; + } + /** Compiler exception .*/ protected final static class CompilerException extends ServletException { -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
