- Add resource injection (note: most annotations are not supported, including web...
authorremm <remm@13f79535-47bb-0310-9956-ffa450edef68>
Sun, 9 Apr 2006 16:38:09 +0000 (16:38 +0000)
committerremm <remm@13f79535-47bb-0310-9956-ffa450edef68>
Sun, 9 Apr 2006 16:38:09 +0000 (16:38 +0000)
  JPA, EJB, etc), as well as PostCreate and PreDestroy.
- If I understand the spec correctly, if using metadata-complete = true, then even PostCreate and
  PreDestroy must be ignored.
- Not tested yet (but it doesn't break when not using annotations).
- Based on a patch submitted by Fabien Carrion.

git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk@392775 13f79535-47bb-0310-9956-ffa450edef68

java/org/apache/catalina/core/ApplicationFilterConfig.java
java/org/apache/catalina/core/NamingContextListener.java
java/org/apache/catalina/core/StandardContext.java
java/org/apache/catalina/core/StandardWrapper.java
java/org/apache/catalina/util/AnnotationProcessor.java [new file with mode: 0644]

index 749c949..9c431b1 100644 (file)
@@ -19,10 +19,12 @@ package org.apache.catalina.core;
 \r
 \r
 import java.io.Serializable;\r
+import java.lang.reflect.InvocationTargetException;\r
 import java.util.ArrayList;\r
 import java.util.Enumeration;\r
 import java.util.Map;\r
 \r
+import javax.naming.NamingException;\r
 import javax.servlet.Filter;\r
 import javax.servlet.FilterConfig;\r
 import javax.servlet.ServletContext;\r
@@ -31,6 +33,7 @@ import javax.servlet.ServletException;
 import org.apache.catalina.Context;\r
 import org.apache.catalina.deploy.FilterDef;\r
 import org.apache.catalina.security.SecurityUtil;\r
+import org.apache.catalina.util.AnnotationProcessor;\r
 import org.apache.catalina.util.Enumerator;\r
 import org.apache.tomcat.util.log.SystemLogHandler;\r
 \r
@@ -66,11 +69,13 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable {
      * @exception InstantiationException if an exception occurs while\r
      *  instantiating the filter object\r
      * @exception ServletException if thrown by the filter's init() method\r
+     * @throws NamingException \r
+     * @throws InvocationTargetException \r
      */\r
     public ApplicationFilterConfig(Context context, FilterDef filterDef)\r
         throws ClassCastException, ClassNotFoundException,\r
                IllegalAccessException, InstantiationException,\r
-               ServletException {\r
+               ServletException, InvocationTargetException, NamingException {\r
 \r
         super();\r
         this.context = context;\r
@@ -186,9 +191,12 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable {
      * @exception InstantiationException if an exception occurs while\r
      *  instantiating the filter object\r
      * @exception ServletException if thrown by the filter's init() method\r
+     * @throws NamingException \r
+     * @throws InvocationTargetException \r
      */\r
     Filter getFilter() throws ClassCastException, ClassNotFoundException,\r
-        IllegalAccessException, InstantiationException, ServletException {\r
+        IllegalAccessException, InstantiationException, ServletException, \r
+        InvocationTargetException, NamingException {\r
 \r
         // Return the existing filter instance, if any\r
         if (this.filter != null)\r
@@ -208,8 +216,16 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable {
         // Instantiate a new instance of this filter and return it\r
         Class clazz = classLoader.loadClass(filterClass);\r
         this.filter = (Filter) clazz.newInstance();\r
+        if (!context.getIgnoreAnnotations()) {\r
+            if (context instanceof StandardContext \r
+                    && ((StandardContext) context).getNamingContextListener() != null) {\r
+                AnnotationProcessor.injectNamingResources\r
+                    (((StandardContext) context).getNamingContextListener().getEnvContext(), this.filter);\r
+            }\r
+            AnnotationProcessor.postConstruct(this.filter);\r
+        }\r
         if (context instanceof StandardContext &&\r
-            ((StandardContext)context).getSwallowOutput()) {\r
+            ((StandardContext) context).getSwallowOutput()) {\r
             try {\r
                 SystemLogHandler.startCapture();\r
                 filter.init(this);\r
@@ -244,8 +260,8 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable {
     void release() {\r
 \r
         if (this.filter != null){\r
-             if( System.getSecurityManager() != null) {\r
-                try{\r
+            if (System.getSecurityManager() != null) {\r
+                try {\r
                     SecurityUtil.doAsPrivilege("destroy", filter); \r
                 } catch(java.lang.Exception ex){                    \r
                     context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex);\r
@@ -254,6 +270,13 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable {
             } else { \r
                 filter.destroy();\r
             }\r
+            if (!context.getIgnoreAnnotations()) {\r
+                try {\r
+                    AnnotationProcessor.preDestroy(this.filter);\r
+                } catch (Exception e) {\r
+                    context.getLogger().error("ApplicationFilterConfig.preDestroy", e);\r
+                }\r
+            }\r
         }\r
         this.filter = null;\r
 \r
@@ -274,18 +297,20 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable {
      * @exception InstantiationException if an exception occurs while\r
      *  instantiating the filter object\r
      * @exception ServletException if thrown by the filter's init() method\r
+     * @throws NamingException \r
+     * @throws InvocationTargetException \r
      */\r
     void setFilterDef(FilterDef filterDef)\r
         throws ClassCastException, ClassNotFoundException,\r
                IllegalAccessException, InstantiationException,\r
-               ServletException {\r
+               ServletException, InvocationTargetException, NamingException {\r
 \r
         this.filterDef = filterDef;\r
         if (filterDef == null) {\r
 \r
             // Release any previously allocated filter instance\r
             if (this.filter != null){\r
-                 if( System.getSecurityManager() != null) {\r
+                if( System.getSecurityManager() != null) {\r
                     try{\r
                         SecurityUtil.doAsPrivilege("destroy", filter);  \r
                     } catch(java.lang.Exception ex){    \r
@@ -295,6 +320,13 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable {
                 } else { \r
                     filter.destroy();\r
                 }\r
+                if (!context.getIgnoreAnnotations()) {\r
+                    try {\r
+                        AnnotationProcessor.preDestroy(this.filter);\r
+                    } catch (Exception e) {\r
+                        context.getLogger().error("ApplicationFilterConfig.preDestroy", e);\r
+                    }\r
+                }\r
             }\r
             this.filter = null;\r
 \r
index c5a9d35..108c047 100644 (file)
@@ -165,6 +165,14 @@ public class NamingContextListener
             log.debug( "setName " + name);\r
     }\r
 \r
+    \r
+    /**\r
+     * Return the env context.\r
+     */\r
+    public javax.naming.Context getEnvContext() {\r
+        return this.envCtx;\r
+    }\r
+    \r
 \r
     /**\r
      * Return the associated naming context.\r
index bf33c18..7115703 100644 (file)
@@ -84,6 +84,7 @@ import org.apache.catalina.loader.WebappLoader;
 import org.apache.catalina.session.StandardManager;\r
 import org.apache.catalina.startup.ContextConfig;\r
 import org.apache.catalina.startup.TldConfig;\r
+import org.apache.catalina.util.AnnotationProcessor;\r
 import org.apache.catalina.util.CharsetMapper;\r
 import org.apache.catalina.util.ExtensionValidator;\r
 import org.apache.catalina.util.RequestUtil;\r
@@ -3710,6 +3711,14 @@ public class StandardContext
             try {\r
                 Class clazz = loader.loadClass(listeners[i]);\r
                 results[i] = clazz.newInstance();\r
+                // Annotation processing\r
+                if (!getIgnoreAnnotations()) {\r
+                    if (getNamingContextListener() != null) {\r
+                        AnnotationProcessor.injectNamingResources\r
+                            (getNamingContextListener().getEnvContext(), results[i]);\r
+                    }\r
+                    AnnotationProcessor.postConstruct(results[i]);\r
+                }\r
             } catch (Throwable t) {\r
                 getLogger().error\r
                     (sm.getString("standardContext.applicationListener",\r
@@ -3787,31 +3796,60 @@ public class StandardContext
 \r
         boolean ok = true;\r
         Object listeners[] = getApplicationLifecycleListeners();\r
-        if (listeners == null)\r
-            return (ok);\r
-        ServletContextEvent event =\r
-          new ServletContextEvent(getServletContext());\r
-        for (int i = 0; i < listeners.length; i++) {\r
-            int j = (listeners.length - 1) - i;\r
-            if (listeners[j] == null)\r
-                continue;\r
-            if (!(listeners[j] instanceof ServletContextListener))\r
-                continue;\r
-            ServletContextListener listener =\r
-                (ServletContextListener) listeners[j];\r
-            try {\r
-                fireContainerEvent("beforeContextDestroyed", listener);\r
-                listener.contextDestroyed(event);\r
-                fireContainerEvent("afterContextDestroyed", listener);\r
-            } catch (Throwable t) {\r
-                fireContainerEvent("afterContextDestroyed", listener);\r
-                getLogger().error\r
-                    (sm.getString("standardContext.listenerStop",\r
-                                  listeners[j].getClass().getName()), t);\r
-                ok = false;\r
+        if (listeners != null) {\r
+            ServletContextEvent event =\r
+                new ServletContextEvent(getServletContext());\r
+            for (int i = 0; i < listeners.length; i++) {\r
+                int j = (listeners.length - 1) - i;\r
+                if (listeners[j] == null)\r
+                    continue;\r
+                if (listeners[j] instanceof ServletContextListener) {\r
+                    ServletContextListener listener =\r
+                        (ServletContextListener) listeners[j];\r
+                    try {\r
+                        fireContainerEvent("beforeContextDestroyed", listener);\r
+                        listener.contextDestroyed(event);\r
+                        fireContainerEvent("afterContextDestroyed", listener);\r
+                    } catch (Throwable t) {\r
+                        fireContainerEvent("afterContextDestroyed", listener);\r
+                        getLogger().error\r
+                            (sm.getString("standardContext.listenerStop",\r
+                                listeners[j].getClass().getName()), t);\r
+                        ok = false;\r
+                    }\r
+                }\r
+                // Annotation processing\r
+                if (!getIgnoreAnnotations()) {\r
+                    try {\r
+                        AnnotationProcessor.preDestroy(listeners[j]);\r
+                    } catch (Throwable t) {\r
+                        getLogger().error\r
+                            (sm.getString("standardContext.listenerStop",\r
+                                listeners[j].getClass().getName()), t);\r
+                        ok = false;\r
+                    }\r
+                }\r
             }\r
         }\r
 \r
+        // Annotation processing\r
+        listeners = getApplicationEventListeners();\r
+        if (!getIgnoreAnnotations() && listeners != null) {\r
+            for (int i = 0; i < listeners.length; i++) {\r
+                int j = (listeners.length - 1) - i;\r
+                if (listeners[j] == null)\r
+                    continue;\r
+                try {\r
+                    AnnotationProcessor.preDestroy(listeners[j]);\r
+                } catch (Throwable t) {\r
+                    getLogger().error\r
+                        (sm.getString("standardContext.listenerStop",\r
+                            listeners[j].getClass().getName()), t);\r
+                    ok = false;\r
+                }\r
+            }\r
+        }\r
+        \r
         setApplicationEventListeners(null);\r
         setApplicationLifecycleListeners(null);\r
 \r
@@ -4794,6 +4832,14 @@ public class StandardContext
     return namingContextName;\r
     }\r
 \r
+    \r
+    /**\r
+     * Naming context listener accessor.\r
+     */\r
+    public NamingContextListener getNamingContextListener() {\r
+        return namingContextListener;\r
+    }\r
+    \r
 \r
     /**\r
      * Return the request processing paused flag for this Context.\r
index 96b8734..c107ef8 100644 (file)
@@ -53,6 +53,7 @@ import org.apache.catalina.LifecycleException;
 import org.apache.catalina.Loader;\r
 import org.apache.catalina.Wrapper;\r
 import org.apache.catalina.security.SecurityUtil;\r
+import org.apache.catalina.util.AnnotationProcessor;\r
 import org.apache.catalina.util.Enumerator;\r
 import org.apache.catalina.util.InstanceSupport;\r
 import org.apache.tomcat.util.IntrospectionUtils;\r
@@ -1053,6 +1054,15 @@ public class StandardWrapper
             // Instantiate and initialize an instance of the servlet class itself\r
             try {\r
                 servlet = (Servlet) classClass.newInstance();\r
+                // Annotation processing\r
+                if (!((Context) getParent()).getIgnoreAnnotations()) {\r
+                    if (getParent() instanceof StandardContext \r
+                            && ((StandardContext) getParent()).getNamingContextListener() != null) {\r
+                        AnnotationProcessor.injectNamingResources\r
+                            (((StandardContext) getParent()).getNamingContextListener().getEnvContext(), servlet);\r
+                    }\r
+                    AnnotationProcessor.postConstruct(servlet);\r
+                }\r
             } catch (ClassCastException e) {\r
                 unavailable(null);\r
                 // Restore the context ClassLoader\r
@@ -1330,9 +1340,15 @@ public class StandardWrapper
             } else {\r
                 instance.destroy();\r
             }\r
-\r
+            \r
             instanceSupport.fireInstanceEvent\r
               (InstanceEvent.AFTER_DESTROY_EVENT, instance);\r
+\r
+            // Annotation processing\r
+            if (!((Context) getParent()).getIgnoreAnnotations()) {\r
+                AnnotationProcessor.preDestroy(instance);\r
+            }\r
+\r
         } catch (Throwable t) {\r
             instanceSupport.fireInstanceEvent\r
               (InstanceEvent.AFTER_DESTROY_EVENT, instance, t);\r
@@ -1367,12 +1383,16 @@ public class StandardWrapper
             try {\r
                 Thread.currentThread().setContextClassLoader(classLoader);\r
                 while (!instancePool.isEmpty()) {\r
-                    if( System.getSecurityManager() != null) {\r
-                        SecurityUtil.doAsPrivilege("destroy",\r
-                                                   ((Servlet) instancePool.pop()));\r
+                    Servlet s = (Servlet) instancePool.pop();\r
+                    if (System.getSecurityManager() != null) {\r
+                        SecurityUtil.doAsPrivilege("destroy", s);\r
                         SecurityUtil.remove(instance);                           \r
                     } else {\r
-                        ((Servlet) instancePool.pop()).destroy();\r
+                        s.destroy();\r
+                    }\r
+                    // Annotation processing\r
+                    if (!((Context) getParent()).getIgnoreAnnotations()) {\r
+                        AnnotationProcessor.preDestroy(s);\r
                     }\r
                 }\r
             } catch (Throwable t) {\r
diff --git a/java/org/apache/catalina/util/AnnotationProcessor.java b/java/org/apache/catalina/util/AnnotationProcessor.java
new file mode 100644 (file)
index 0000000..1524b5b
--- /dev/null
@@ -0,0 +1,205 @@
+/*\r
+ * Copyright 1999,2004 The Apache Software Foundation.\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package org.apache.catalina.util;\r
+\r
+import java.lang.reflect.Field;\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+import java.lang.reflect.Modifier;\r
+\r
+import javax.annotation.PostConstruct;\r
+import javax.annotation.Resource;\r
+import javax.naming.NamingException;\r
+\r
+import org.apache.tomcat.util.IntrospectionUtils;\r
+\r
+\r
+/**\r
+ * Verify the annotation and Process it.\r
+ *\r
+ * @author    Fabien Carrion\r
+ * @version   $Revision: 303236 $, $Date: 2006-03-09 16:46:52 -0600 (Thu, 09 Mar 2006) $\r
+ */\r
+public class AnnotationProcessor {\r
+    \r
+\r
+    /**\r
+     * Call postConstruct method on the specified instance.\r
+     */\r
+    public static void postConstruct(Object instance)\r
+        throws IllegalAccessException, InvocationTargetException {\r
+        \r
+        Method[] methods = IntrospectionUtils.findMethods(instance.getClass());\r
+        Method postConstruct = null;\r
+        for (int i = 0; i < methods.length; i++) {\r
+            if (methods[i].isAnnotationPresent(PostConstruct.class)) {\r
+                if ((postConstruct != null) \r
+                        || (methods[i].getParameterTypes().length != 0)\r
+                        || (Modifier.isStatic(methods[i].getModifiers())) \r
+                        || (methods[i].getExceptionTypes().length > 0)\r
+                        || (!methods[i].getReturnType().getName().equals("void"))) {\r
+                    throw new IllegalArgumentException("Invalid PostConstruct annotation");\r
+                }\r
+                postConstruct = methods[i];\r
+            }\r
+        }\r
+\r
+        // At the end the postconstruct annotated \r
+        // method is invoked\r
+        if (postConstruct != null) {\r
+            boolean accessibility = postConstruct.isAccessible();\r
+            postConstruct.setAccessible(true);\r
+            postConstruct.invoke(instance);\r
+            postConstruct.setAccessible(accessibility);\r
+        }\r
+        \r
+    }\r
+    \r
+    \r
+    /**\r
+     * Call preDestroy method on the specified instance.\r
+     */\r
+    public static void preDestroy(Object instance)\r
+        throws IllegalAccessException, InvocationTargetException {\r
+        \r
+        Method[] methods = IntrospectionUtils.findMethods(instance.getClass());\r
+        Method preDestroy = null;\r
+        for (int i = 0; i < methods.length; i++) {\r
+            if (methods[i].isAnnotationPresent(PostConstruct.class)) {\r
+                if ((preDestroy != null) \r
+                        || (methods[i].getParameterTypes().length != 0)\r
+                        || (Modifier.isStatic(methods[i].getModifiers())) \r
+                        || (methods[i].getExceptionTypes().length > 0)\r
+                        || (!methods[i].getReturnType().getName().equals("void"))) {\r
+                    throw new IllegalArgumentException("Invalid PreDestroy annotation");\r
+                }\r
+                preDestroy = methods[i];\r
+            }\r
+        }\r
+\r
+        // At the end the postconstruct annotated \r
+        // method is invoked\r
+        if (preDestroy != null) {\r
+            boolean accessibility = preDestroy.isAccessible();\r
+            preDestroy.setAccessible(true);\r
+            preDestroy.invoke(instance);\r
+            preDestroy.setAccessible(accessibility);\r
+        }\r
+        \r
+    }\r
+    \r
+    \r
+    /**\r
+     * Inject resources in specified instance.\r
+     */\r
+    public static void injectNamingResources(javax.naming.Context context, Object instance)\r
+        throws IllegalAccessException, InvocationTargetException, NamingException {\r
+        \r
+        // Initialize fields annotations\r
+        Field[] fields = instance.getClass().getFields();\r
+        for (int i = 0; i < fields.length; i++) {\r
+            if (fields[i].isAnnotationPresent(Resource.class)) {\r
+                Resource annotation = (Resource) fields[i].getAnnotation(Resource.class);\r
+                lookupFieldResource(context, instance, fields[i], annotation.name());\r
+            }\r
+            /*\r
+            if (f.isAnnotationPresent(EJB.class)) {\r
+                EJB annotation = (EJB) f.getAnnotation(EJB.class);\r
+                lookupOnFieldResource(f, annotation.name());\r
+            }\r
+            \r
+            if (f.isAnnotationPresent(WebServiceRef.class)) {\r
+                WebServiceRef annotation = (WebServiceRef) \r
+                f.getAnnotation(WebServiceRef.class);\r
+                lookupOnFieldResource(f, annotation.name());\r
+            }\r
+            */\r
+        }\r
+        \r
+        // Initialize methods annotations\r
+        Method[] methods = IntrospectionUtils.findMethods(instance.getClass());\r
+        for (int i = 0; i < methods.length; i++) {\r
+            if (methods[i].isAnnotationPresent(Resource.class)) {\r
+                Resource annotation = (Resource) methods[i].getAnnotation(Resource.class);\r
+                lookupMethodResource(context, instance, methods[i], annotation.name());\r
+            }\r
+            /*\r
+            if (m.isAnnotationPresent(EJB.class)) {\r
+                EJB annotation = (EJB) m.getAnnotation(EJB.class);\r
+                lookupOnMethodResource(m, annotation.name());\r
+            }\r
+            if (m.isAnnotationPresent(WebServiceRef.class)) {\r
+                WebServiceRef annotation = (WebServiceRef) \r
+                m.getAnnotation(WebServiceRef.class);\r
+                lookupOnMethodResource(m, annotation.name());\r
+            }\r
+            */\r
+        }            \r
+\r
+    }\r
+    \r
+    \r
+    protected static void lookupFieldResource(javax.naming.Context context, \r
+            Object instance, Field f, String name)\r
+        throws NamingException, IllegalAccessException {\r
+    \r
+        Object lookedupResource = null;\r
+        boolean accessibility = false;\r
+        \r
+        if ((name != null) &&\r
+                (name.length() > 0)) {\r
+            lookedupResource = context.lookup(name);\r
+        } else {\r
+            lookedupResource = context.lookup(instance.getClass().getName() + "/" + f.getName());\r
+        }\r
+        \r
+        accessibility = f.isAccessible();\r
+        f.setAccessible(true);\r
+        f.set(instance, lookedupResource);\r
+        f.setAccessible(accessibility);\r
+    }\r
+\r
+\r
+    protected static void lookupMethodResource(javax.naming.Context context, \r
+            Object instance, Method method, String name)\r
+        throws NamingException, IllegalAccessException, InvocationTargetException {\r
+        \r
+        if (!method.getName().startsWith("set") \r
+                || method.getParameterTypes().length != 1\r
+                || !method.getReturnType().getName().equals("void")) {\r
+            throw new IllegalArgumentException("Invalid method resource injection annotation");\r
+        }\r
+        \r
+        Object lookedupResource = null;\r
+        boolean accessibility = false;\r
+        \r
+        if ((name != null) &&\r
+                (name.length() > 0)) {\r
+            lookedupResource = context.lookup(name);\r
+        } else {\r
+            lookedupResource = \r
+                context.lookup(instance.getClass().getName() + "/" + method.getName().substring(3));\r
+        }\r
+        \r
+        accessibility = method.isAccessible();\r
+        method.setAccessible(true);\r
+        method.invoke(instance, lookedupResource);\r
+        method.setAccessible(accessibility);\r
+    }\r
+    \r
+\r
+}\r