Return-Path: X-Original-To: apmail-sling-commits-archive@www.apache.org Delivered-To: apmail-sling-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 6396896B1 for ; Wed, 5 Oct 2011 21:36:10 +0000 (UTC) Received: (qmail 14820 invoked by uid 500); 5 Oct 2011 21:36:10 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 14772 invoked by uid 500); 5 Oct 2011 21:36:10 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 14765 invoked by uid 99); 5 Oct 2011 21:36:10 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 05 Oct 2011 21:36:10 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 05 Oct 2011 21:36:06 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id E18802388AB8; Wed, 5 Oct 2011 21:35:44 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1179454 - in /sling/trunk/contrib/scripting/java: pom.xml src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java src/main/java/org/apache/sling/scripting/java/impl/ServletWrapper.java Date: Wed, 05 Oct 2011 21:35:44 -0000 To: commits@sling.apache.org From: justin@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20111005213544.E18802388AB8@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: justin Date: Wed Oct 5 21:35:44 2011 New Revision: 1179454 URL: http://svn.apache.org/viewvc?rev=1179454&view=rev Log: SLING-2237 - initial implementation of @Inject support Modified: sling/trunk/contrib/scripting/java/pom.xml sling/trunk/contrib/scripting/java/src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java sling/trunk/contrib/scripting/java/src/main/java/org/apache/sling/scripting/java/impl/ServletWrapper.java Modified: sling/trunk/contrib/scripting/java/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/java/pom.xml?rev=1179454&r1=1179453&r2=1179454&view=diff ============================================================================== --- sling/trunk/contrib/scripting/java/pom.xml (original) +++ sling/trunk/contrib/scripting/java/pom.xml Wed Oct 5 21:35:44 2011 @@ -23,7 +23,7 @@ org.apache.sling sling - 11 + 12 ../../../parent/pom.xml @@ -55,8 +55,9 @@ org.apache.sling.scripting.java.impl - ${pom.name} - ${pom.version} + ${project.name} + ${project.version} + javax.inject @@ -123,5 +124,10 @@ org.slf4j slf4j-api + + javax.inject + javax.inject + 1 + Modified: sling/trunk/contrib/scripting/java/src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/java/src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java?rev=1179454&r1=1179453&r2=1179454&view=diff ============================================================================== --- sling/trunk/contrib/scripting/java/src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java (original) +++ sling/trunk/contrib/scripting/java/src/main/java/org/apache/sling/scripting/java/impl/JavaScriptEngineFactory.java Wed Oct 5 21:35:44 2011 @@ -238,7 +238,8 @@ public class JavaScriptEngineFactory wrapper = new ServletWrapper(servletConfig, ioProvider, - scriptName); + scriptName, + scriptHelper); this.ioProvider.getServletCache().addWrapper(scriptName, wrapper); return wrapper; Modified: sling/trunk/contrib/scripting/java/src/main/java/org/apache/sling/scripting/java/impl/ServletWrapper.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/java/src/main/java/org/apache/sling/scripting/java/impl/ServletWrapper.java?rev=1179454&r1=1179453&r2=1179454&view=diff ============================================================================== --- sling/trunk/contrib/scripting/java/src/main/java/org/apache/sling/scripting/java/impl/ServletWrapper.java (original) +++ sling/trunk/contrib/scripting/java/src/main/java/org/apache/sling/scripting/java/impl/ServletWrapper.java Wed Oct 5 21:35:44 2011 @@ -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.UnavailableExceptio 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 {