Coverage Report - org.apache.myfaces.spi.impl.NoInjectionAnnotationInjectionProvider
 
Classes in this File Line Coverage Branch Coverage Complexity
NoInjectionAnnotationInjectionProvider
0%
0/76
0%
0/38
5.375
 
 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.spi.impl;
 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  
 import org.apache.myfaces.spi.InjectionProvider;
 34  
 import org.apache.myfaces.spi.InjectionProviderException;
 35  
 
 36  
 /**
 37  
  * See SRV.14.5 Servlet Specification Version 2.5 JSR 154
 38  
  * and Common Annotations for the Java Platform JSR 250
 39  
 
 40  
  */
 41  
 
 42  0
 public class NoInjectionAnnotationInjectionProvider extends InjectionProvider
 43  
 {
 44  
      /**
 45  
      * Cache the Method instances per ClassLoader using the Class-Name.
 46  
      * NOTE that we do it this way, because the only other valid way in order to support a shared
 47  
      * classloader scenario would be to use a WeakHashMap<Class<?>, Method[]>, but this
 48  
      * creates a cyclic reference between the key and the value of the WeakHashMap which will
 49  
      * most certainly cause a memory leak! Furthermore we can manually cleanup the Map when
 50  
      * the webapp is undeployed just by removing the Map for the current ClassLoader. 
 51  
      */
 52  0
     private volatile static WeakHashMap<ClassLoader, Map<Class,Method[]> > declaredMethodBeans = 
 53  
             new WeakHashMap<ClassLoader, Map<Class, Method[]>>();
 54  
 
 55  
     private static Map<Class,Method[]> getDeclaredMethodBeansMap()
 56  
     {
 57  0
         ClassLoader cl = ClassUtils.getContextClassLoader();
 58  
         
 59  0
         Map<Class,Method[]> metadata = (Map<Class,Method[]>)
 60  
                 declaredMethodBeans.get(cl);
 61  
 
 62  0
         if (metadata == null)
 63  
         {
 64  
             // Ensure thread-safe put over _metadata, and only create one map
 65  
             // per classloader to hold metadata.
 66  0
             synchronized (declaredMethodBeans)
 67  
             {
 68  0
                 metadata = createDeclaredMethodBeansMap(cl, metadata);
 69  0
             }
 70  
         }
 71  
 
 72  0
         return metadata;
 73  
     }
 74  
     
 75  
     private static Map<Class,Method[]> createDeclaredMethodBeansMap(
 76  
             ClassLoader cl, Map<Class,Method[]> metadata)
 77  
     {
 78  0
         metadata = (Map<Class,Method[]>) declaredMethodBeans.get(cl);
 79  0
         if (metadata == null)
 80  
         {
 81  0
             metadata = new HashMap<Class,Method[]>();
 82  0
             declaredMethodBeans.put(cl, metadata);
 83  
         }
 84  0
         return metadata;
 85  
     }
 86  
 
 87  
     @Override
 88  
     public Object inject(Object instance) throws InjectionProviderException
 89  
     {
 90  
         try
 91  
         {
 92  0
             processAnnotations(instance);
 93  
         }
 94  0
         catch (IllegalAccessException ex)
 95  
         {
 96  0
             throw new InjectionProviderException(ex);
 97  
         }
 98  0
         catch (InvocationTargetException ex)
 99  
         {
 100  0
             throw new InjectionProviderException(ex);
 101  
         }
 102  0
         catch (NamingException ex)
 103  
         {
 104  0
             throw new InjectionProviderException(ex);
 105  0
         }
 106  0
         return null;
 107  
     }
 108  
     
 109  
     
 110  
     Method[] getDeclaredMethods(Class clazz)
 111  
     {
 112  0
         Map<Class,Method[]> declaredMethodBeansMap = getDeclaredMethodBeansMap();
 113  0
         Method[] methods = declaredMethodBeansMap.get(clazz);
 114  0
         if (methods == null)
 115  
         {
 116  0
             methods = clazz.getDeclaredMethods();
 117  0
             synchronized(declaredMethodBeansMap)
 118  
             {
 119  0
                 declaredMethodBeansMap.put(clazz, methods);
 120  0
             }
 121  
         }
 122  0
         return methods;
 123  
     }
 124  
 
 125  
     /**
 126  
      * Call postConstruct method on the specified instance.
 127  
      */
 128  
     @Override
 129  
     public void postConstruct(Object instance, Object creationMetaData) throws InjectionProviderException
 130  
     {
 131  
         // TODO the servlet spec is not clear about searching in superclass??
 132  0
         Class clazz = instance.getClass();
 133  0
         Method[] methods = getDeclaredMethods(clazz);
 134  0
         if (methods == null)
 135  
         {
 136  0
             methods = clazz.getDeclaredMethods();
 137  0
             Map<Class,Method[]> declaredMethodBeansMap = getDeclaredMethodBeansMap();
 138  0
             synchronized(declaredMethodBeansMap)
 139  
             {
 140  0
                 declaredMethodBeansMap.put(clazz, methods);
 141  0
             }
 142  
         }
 143  0
         Method postConstruct = null;
 144  0
         for (int i = 0; i < methods.length; i++)
 145  
         {
 146  0
             Method method = methods[i];
 147  0
             if (method.isAnnotationPresent(PostConstruct.class))
 148  
             {
 149  
                 // a method that does not take any arguments
 150  
                 // the method must not be static
 151  
                 // must not throw any checked expections
 152  
                 // the return value must be void
 153  
                 // the method may be public, protected, package private or private
 154  
 
 155  0
                 if ((postConstruct != null)
 156  
                         || (method.getParameterTypes().length != 0)
 157  
                         || (Modifier.isStatic(method.getModifiers()))
 158  
                         || (method.getExceptionTypes().length > 0)
 159  
                         || (!method.getReturnType().getName().equals("void")))
 160  
                 {
 161  0
                     throw new IllegalArgumentException("Invalid PostConstruct annotation");
 162  
                 }
 163  0
                 postConstruct = method;
 164  
             }
 165  
         }
 166  
         try
 167  
         {
 168  0
             invokeAnnotatedMethod(postConstruct, instance);
 169  
         }
 170  0
         catch (IllegalAccessException ex)
 171  
         {
 172  0
             throw new InjectionProviderException(ex);
 173  
         }
 174  0
         catch (InvocationTargetException ex)
 175  
         {
 176  0
             throw new InjectionProviderException(ex);
 177  0
         }
 178  0
     }
 179  
 
 180  
     @Override
 181  
     public void preDestroy(Object instance, Object creationMetaData) throws InjectionProviderException
 182  
     {
 183  
 
 184  
         // TODO the servlet spec is not clear about searching in superclass??
 185  
         // May be only check non private fields and methods
 186  0
         Class clazz = instance.getClass();
 187  0
         Method[] methods = getDeclaredMethods(clazz);
 188  0
         Method preDestroy = null;
 189  0
         for (int i = 0; i < methods.length; i++)
 190  
         {
 191  0
             Method method = methods[i];
 192  0
             if (method.isAnnotationPresent(PreDestroy.class))
 193  
             {
 194  
                 // must not throw any checked expections
 195  
                 // the method must not be static
 196  
                 // must not throw any checked expections
 197  
                 // the return value must be void
 198  
                 // the method may be public, protected, package private or private
 199  
 
 200  0
                 if ((preDestroy != null)
 201  
                         || (method.getParameterTypes().length != 0)
 202  
                         || (Modifier.isStatic(method.getModifiers()))
 203  
                         || (method.getExceptionTypes().length > 0)
 204  
                         || (!method.getReturnType().getName().equals("void")))
 205  
                 {
 206  0
                     throw new IllegalArgumentException("Invalid PreDestroy annotation");
 207  
                 }
 208  0
                 preDestroy = method;
 209  
             }
 210  
         }
 211  
 
 212  
         try
 213  
         {
 214  0
             invokeAnnotatedMethod(preDestroy, instance);
 215  
         }
 216  0
         catch (IllegalAccessException ex)
 217  
         {
 218  0
             throw new InjectionProviderException(ex);
 219  
         }
 220  0
         catch (InvocationTargetException ex)
 221  
         {
 222  0
             throw new InjectionProviderException(ex);
 223  0
         }
 224  0
     }
 225  
 
 226  
     private void invokeAnnotatedMethod(Method method, Object instance)
 227  
                 throws IllegalAccessException, InvocationTargetException
 228  
     {
 229  
         // At the end the annotated
 230  
         // method is invoked
 231  0
         if (method != null)
 232  
         {
 233  0
             boolean accessibility = method.isAccessible();
 234  0
             method.setAccessible(true);
 235  0
             method.invoke(instance);
 236  0
             method.setAccessible(accessibility);
 237  
         }
 238  0
     }
 239  
 
 240  
      /**
 241  
      * Inject resources in specified instance.
 242  
      */
 243  
     protected void processAnnotations(Object instance)
 244  
             throws IllegalAccessException, InvocationTargetException, NamingException
 245  
     {
 246  
 
 247  0
     }
 248  
 }