FileDocCategorySizeDatePackage
InjectionUtil.javaAPI DocJBoss 4.2.110389Fri Jul 13 20:53:46 BST 2007org.jboss.injection

InjectionUtil.java

/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2006, Red Hat Middleware LLC, and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.injection;

import org.jboss.ejb3.EJBContainer;
import org.jboss.logging.Logger;
import org.jboss.metamodel.descriptor.InjectionTarget;
import org.jboss.metamodel.descriptor.Ref;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Comment
 *
 * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
 * @version $Revision: 60233 $
 */
public class InjectionUtil
{
   private static final Logger log = Logger
           .getLogger(InjectionUtil.class);


   /**
    * This method will take a set of XML loaded injectors and collapse them based on spec inheritance rules
    * It will remove injectors that should not be used in the injection of the base component class.
    *
    * @param visitedMethods
    * @param clazz
    * @param xmlDefinedInjectors
    * @param classInjectors
    */
   public static void collapseXmlMethodInjectors(Set<String> visitedMethods, Class clazz, Map<String, Map<AccessibleObject, Injector>> xmlDefinedInjectors, Map<AccessibleObject, Injector> classInjectors)
   {
      if (clazz == null || clazz.equals(Object.class))
      {
         return;
      }
      Map<AccessibleObject, Injector> xmlInjectors = xmlDefinedInjectors.get(clazz.getName());
      if (xmlInjectors != null)
      {
         Method[] methods = clazz.getDeclaredMethods();
         for (Method method : methods)
         {
            if (method.getParameterTypes().length != 1) continue;

            if (!Modifier.isPrivate(method.getModifiers()))
            {
               if (visitedMethods.contains(method.getName()))
               {
                  xmlInjectors.remove(method); // if not private then it has been overriden
                  continue;
               }
               visitedMethods.add(method.getName());
            }
         }
         classInjectors.putAll(xmlInjectors);
      }
      // recursion needs to come last as the method could be overriden and we don't want the overriding method to be ignored
      collapseXmlMethodInjectors(visitedMethods, clazz.getSuperclass(), xmlDefinedInjectors, classInjectors);
   }

   public static void processMethodAnnotations(InjectionContainer container, Collection<InjectionHandler> handlers, Set<String> visitedMethods, Class clazz, Map<AccessibleObject, Injector> classInjectors)
   {
      if (clazz == null || clazz.equals(Object.class))
      {
         return;
      }
      Method[] methods = clazz.getDeclaredMethods();
      for (Method method : methods)
      {
         if (method.getParameterTypes().length != 1) continue;

         if (!Modifier.isPrivate(method.getModifiers()))
         {
            if (visitedMethods.contains(method.getName()))
            {
               continue;
            }
            visitedMethods.add(method.getName());
         }
        
         if (handlers != null)
         {
            for (InjectionHandler handler : handlers)
            {
               handler.handleMethodAnnotations(method, container, classInjectors);
            }
         }
      }
      // recursion needs to come last as the method could be overriden and we don't want the overriding method to be ignored
      processMethodAnnotations(container, handlers, visitedMethods, clazz.getSuperclass(), classInjectors);
   }

   public static void processFieldAnnotations(InjectionContainer container, Collection<InjectionHandler> handlers, Class clazz, Map<AccessibleObject, Injector> classInjectors)
   {
      if (clazz == null || clazz.equals(Object.class))
      {
         return;
      }
 
      if (handlers != null)
      {
         Field[] fields = clazz.getDeclaredFields();
         for (Field field : fields)
         {
            log.trace("process field annotation for " + field.toGenericString());
            for (InjectionHandler handler : handlers)
            {
               handler.handleFieldAnnotations(field, container, classInjectors);
            }
         }
      }
      
      // recursion needs to come last as the method could be overriden and we don't want the overriding method to be ignored
      processFieldAnnotations(container, handlers, clazz.getSuperclass(), classInjectors);
   }

   public static void processClassAnnotations(InjectionContainer container, Collection<InjectionHandler> handlers, Class clazz)
   {
      if (clazz == null || clazz.equals(Object.class))
      {
         return;
      }
    
      if (handlers != null)
      {
         for (InjectionHandler handler : handlers)
         {
            handler.handleClassAnnotations(clazz, container);
         }
      }
      
      // recursion needs to come last as the method could be overriden and we don't want the overriding method to be ignored
      processClassAnnotations(container, handlers, clazz.getSuperclass());
   }

   public static Map<AccessibleObject, Injector> processAnnotations(InjectionContainer container, Collection<InjectionHandler> handlers, Class clazz)
   {
      Map<AccessibleObject, Injector> classInjectors = new HashMap<AccessibleObject, Injector>();
      HashSet<String> visitedMethods = new HashSet<String>();
      collapseXmlMethodInjectors(visitedMethods, clazz, container.getEncInjections(), classInjectors);

      processClassAnnotations(container, handlers, clazz);
      visitedMethods = new HashSet<String>();
      processMethodAnnotations(container, handlers, visitedMethods, clazz, classInjectors);
      processFieldAnnotations(container, handlers, clazz, classInjectors);
      return classInjectors;
   }

   public static AccessibleObject findInjectionTarget(ClassLoader loader, InjectionTarget target)
   {
      Class clazz = null;
      try
      {
         clazz = loader.loadClass(target.getTargetClass());
      }
      catch (ClassNotFoundException e)
      {
         throw new RuntimeException("<injection-target> class: " + target.getTargetClass() + " was not found nin deployment");
      }

      for (Field field : clazz.getDeclaredFields())
      {
         if (target.getTargetName().equals(field.getName())) return field;
      }

      for (java.lang.reflect.Method method : clazz.getDeclaredMethods())
      {
         if (method.getName().equals(target.getTargetName())) return method;
      }

      throw new RuntimeException("<injection-target> could not be found: " + target.getTargetClass() + "." + target.getTargetName());

   }

   public static String getEncName(Class type)
   {
      return "env/" + type.getName();
   }

   public static String getEncName(Method method)
   {
      String encName = method.getName().substring(3);
      if (encName.length() > 1)
      {
         encName = encName.substring(0, 1).toLowerCase() + encName.substring(1);
      }
      else
      {
         encName = encName.toLowerCase();
      }

      encName = getEncName(method.getDeclaringClass()) + "/" + encName;
      return encName;
   }

   public static String getEncName(Field field)
   {
      return getEncName(field.getDeclaringClass()) + "/" + field.getName();
   }

   public static Object getAnnotation(Class annotation, EJBContainer container, Class annotatedClass, boolean isContainer)
   {
      if (isContainer)
      {
         return container.resolveAnnotation(annotation);
      }
      else
      {
         return annotatedClass.getAnnotation(annotation);
      }
   }

   public static Object getAnnotation(Class annotation, EJBContainer container, Method method, boolean isContainer)
   {
      if (isContainer)
      {
         return container.resolveAnnotation(method, annotation);
      }
      else
      {
         return method.getAnnotation(annotation);
      }
   }

   public static Object getAnnotation(Class annotation, EJBContainer container, Field field, boolean isContainer)
   {
      if (isContainer)
      {
         return container.resolveAnnotation(field, annotation);
      }
      else
      {
         return field.getAnnotation(annotation);
      }
   }

   public static Class injectionTarget(String encName, Ref ref, InjectionContainer container, Map<String, Map<AccessibleObject, Injector>> classInjectors)
   {
      if (ref.getInjectionTarget() != null)
      {
         Class injectionType;
         // todo, get injection target class
         AccessibleObject ao = findInjectionTarget(container.getClassloader(), ref.getInjectionTarget());
         Map<AccessibleObject, Injector> injectors = classInjectors.get(ref.getInjectionTarget().getTargetClass());
         if (injectors == null)
         {
            injectors = new HashMap<AccessibleObject, Injector>();
            classInjectors.put(ref.getInjectionTarget().getTargetClass().trim(), injectors);
         }
         if (ao instanceof Field)
         {
            injectionType = ((Field) ao).getType();
            injectors.put(ao, new JndiFieldInjector((Field) ao, encName, container.getEnc()));
         }
         else
         {
            injectionType = ((Method) ao).getParameterTypes()[0];
            injectors.put(ao, new JndiMethodInjector((Method) ao, encName, container.getEnc()));
         }
         return injectionType;
      }
      else
      {
         return null;
      }

   }
}