Coverage Report - org.apache.myfaces.config.annotation.NoInjectionAnnotationLifecycleProvider
 
Classes in this File Line Coverage Branch Coverage Complexity
NoInjectionAnnotationLifecycleProvider
0%
0/61
0%
0/38
3.625
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.myfaces.config.annotation;
 20  
 
 21  
 import java.lang.reflect.InvocationTargetException;
 22  
 import java.lang.reflect.Method;
 23  
 import java.lang.reflect.Modifier;
 24  
 
 25  
 import java.util.HashMap;
 26  
 import java.util.Map;
 27  
 import java.util.WeakHashMap;
 28  
 import javax.annotation.PostConstruct;
 29  
 import javax.annotation.PreDestroy;
 30  
 import javax.naming.NamingException;
 31  
 
 32  
 import org.apache.myfaces.shared.util.ClassUtils;
 33  
 
 34  
 /**
 35  
  * See SRV.14.5 Servlet Specification Version 2.5 JSR 154
 36  
  * and Common Annotations for the Java Platform JSR 250
 37  
 
 38  
  */
 39  
 
 40  0
 public class NoInjectionAnnotationLifecycleProvider implements LifecycleProvider2
 41  
 {
 42  
      /**
 43  
      * Cache the Method instances per ClassLoader using the Class-Name.
 44  
      * NOTE that we do it this way, because the only other valid way in order to support a shared
 45  
      * classloader scenario would be to use a WeakHashMap<Class<?>, Method[]>, but this
 46  
      * creates a cyclic reference between the key and the value of the WeakHashMap which will
 47  
      * most certainly cause a memory leak! Furthermore we can manually cleanup the Map when
 48  
      * the webapp is undeployed just by removing the Map for the current ClassLoader. 
 49  
      */
 50  0
     private volatile static WeakHashMap<ClassLoader, Map<Class,Method[]> > declaredMethodBeans = 
 51  
             new WeakHashMap<ClassLoader, Map<Class, Method[]>>();
 52  
 
 53  
     private static Map<Class,Method[]> getDeclaredMethodBeansMap()
 54  
     {
 55  0
         ClassLoader cl = ClassUtils.getContextClassLoader();
 56  
         
 57  0
         Map<Class,Method[]> metadata = (Map<Class,Method[]>)
 58  
                 declaredMethodBeans.get(cl);
 59  
 
 60  0
         if (metadata == null)
 61  
         {
 62  
             // Ensure thread-safe put over _metadata, and only create one map
 63  
             // per classloader to hold metadata.
 64  0
             synchronized (declaredMethodBeans)
 65  
             {
 66  0
                 metadata = createDeclaredMethodBeansMap(cl, metadata);
 67  0
             }
 68  
         }
 69  
 
 70  0
         return metadata;
 71  
     }
 72  
     
 73  
     private static Map<Class,Method[]> createDeclaredMethodBeansMap(
 74  
             ClassLoader cl, Map<Class,Method[]> metadata)
 75  
     {
 76  0
         metadata = (Map<Class,Method[]>) declaredMethodBeans.get(cl);
 77  0
         if (metadata == null)
 78  
         {
 79  0
             metadata = new HashMap<Class,Method[]>();
 80  0
             declaredMethodBeans.put(cl, metadata);
 81  
         }
 82  0
         return metadata;
 83  
     }
 84  
 
 85  
     public Object newInstance(String className)
 86  
            throws InstantiationException, IllegalAccessException, NamingException,
 87  
             InvocationTargetException, ClassNotFoundException
 88  
     {
 89  0
         Class clazz = ClassUtils.classForName(className);
 90  0
         Object object = clazz.newInstance();
 91  0
         processAnnotations(object);
 92  
         //postConstruct(object);
 93  0
         return object;
 94  
     }
 95  
     
 96  
     
 97  
     Method[] getDeclaredMethods(Class clazz)
 98  
     {
 99  0
         Map<Class,Method[]> declaredMethodBeansMap = getDeclaredMethodBeansMap();
 100  0
         Method[] methods = declaredMethodBeansMap.get(clazz);
 101  0
         if (methods == null)
 102  
         {
 103  0
             methods = clazz.getDeclaredMethods();
 104  0
             synchronized(declaredMethodBeansMap)
 105  
             {
 106  0
                 declaredMethodBeansMap.put(clazz, methods);
 107  0
             }
 108  
         }
 109  0
         return methods;
 110  
     }
 111  
 
 112  
     /**
 113  
      * Call postConstruct method on the specified instance.
 114  
      */
 115  
     public void postConstruct(Object instance)
 116  
             throws IllegalAccessException, InvocationTargetException
 117  
     {
 118  
         // TODO the servlet spec is not clear about searching in superclass??
 119  0
         Class clazz = instance.getClass();
 120  0
         Method[] methods = getDeclaredMethods(clazz);
 121  0
         if (methods == null)
 122  
         {
 123  0
             methods = clazz.getDeclaredMethods();
 124  0
             Map<Class,Method[]> declaredMethodBeansMap = getDeclaredMethodBeansMap();
 125  0
             synchronized(declaredMethodBeansMap)
 126  
             {
 127  0
                 declaredMethodBeansMap.put(clazz, methods);
 128  0
             }
 129  
         }
 130  0
         Method postConstruct = null;
 131  0
         for (int i = 0; i < methods.length; i++)
 132  
         {
 133  0
             Method method = methods[i];
 134  0
             if (method.isAnnotationPresent(PostConstruct.class))
 135  
             {
 136  
                 // a method that does not take any arguments
 137  
                 // the method must not be static
 138  
                 // must not throw any checked expections
 139  
                 // the return value must be void
 140  
                 // the method may be public, protected, package private or private
 141  
 
 142  0
                 if ((postConstruct != null)
 143  
                         || (method.getParameterTypes().length != 0)
 144  
                         || (Modifier.isStatic(method.getModifiers()))
 145  
                         || (method.getExceptionTypes().length > 0)
 146  
                         || (!method.getReturnType().getName().equals("void")))
 147  
                 {
 148  0
                     throw new IllegalArgumentException("Invalid PostConstruct annotation");
 149  
                 }
 150  0
                 postConstruct = method;
 151  
             }
 152  
         }
 153  
 
 154  0
         invokeAnnotatedMethod(postConstruct, instance);
 155  
 
 156  0
     }
 157  
 
 158  
     public void destroyInstance(Object instance)
 159  
             throws IllegalAccessException, InvocationTargetException
 160  
     {
 161  
 
 162  
         // TODO the servlet spec is not clear about searching in superclass??
 163  
         // May be only check non private fields and methods
 164  0
         Class clazz = instance.getClass();
 165  0
         Method[] methods = getDeclaredMethods(clazz);
 166  0
         Method preDestroy = null;
 167  0
         for (int i = 0; i < methods.length; i++)
 168  
         {
 169  0
             Method method = methods[i];
 170  0
             if (method.isAnnotationPresent(PreDestroy.class))
 171  
             {
 172  
                 // must not throw any checked expections
 173  
                 // the method must not be static
 174  
                 // must not throw any checked expections
 175  
                 // the return value must be void
 176  
                 // the method may be public, protected, package private or private
 177  
 
 178  0
                 if ((preDestroy != null)
 179  
                         || (method.getParameterTypes().length != 0)
 180  
                         || (Modifier.isStatic(method.getModifiers()))
 181  
                         || (method.getExceptionTypes().length > 0)
 182  
                         || (!method.getReturnType().getName().equals("void")))
 183  
                 {
 184  0
                     throw new IllegalArgumentException("Invalid PreDestroy annotation");
 185  
                 }
 186  0
                 preDestroy = method;
 187  
             }
 188  
         }
 189  
 
 190  0
         invokeAnnotatedMethod(preDestroy, instance);
 191  
 
 192  0
     }
 193  
 
 194  
     private void invokeAnnotatedMethod(Method method, Object instance)
 195  
                 throws IllegalAccessException, InvocationTargetException
 196  
     {
 197  
         // At the end the annotated
 198  
         // method is invoked
 199  0
         if (method != null)
 200  
         {
 201  0
             boolean accessibility = method.isAccessible();
 202  0
             method.setAccessible(true);
 203  0
             method.invoke(instance);
 204  0
             method.setAccessible(accessibility);
 205  
         }
 206  0
     }
 207  
 
 208  
      /**
 209  
      * Inject resources in specified instance.
 210  
      */
 211  
     protected void processAnnotations(Object instance)
 212  
             throws IllegalAccessException, InvocationTargetException, NamingException
 213  
     {
 214  
 
 215  0
     }
 216  
 
 217  
 }