You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 10:04:45 UTC

[sling-org-apache-sling-scripting-java] 12/43: SLING-2237 - initial implementation of @Inject support

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 <ju...@apache.org>
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
"commits@sling.apache.org" <co...@sling.apache.org>.