Package org.jboss.wsf.common.injection

Source Code of org.jboss.wsf.common.injection.InjectionHelper

/*
* JBoss, Home of Professional Open Source.
* Copyright 2009, 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.wsf.common.injection;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;

import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.xml.ws.WebServiceContext;

import org.jboss.logging.Logger;
import org.jboss.wsf.common.injection.finders.EJBFieldFinder;
import org.jboss.wsf.common.injection.finders.EJBMethodFinder;
import org.jboss.wsf.common.injection.finders.InjectionFieldFinder;
import org.jboss.wsf.common.injection.finders.InjectionMethodFinder;
import org.jboss.wsf.common.injection.finders.PostConstructMethodFinder;
import org.jboss.wsf.common.injection.finders.PreDestroyMethodFinder;
import org.jboss.wsf.common.injection.finders.ResourceFieldFinder;
import org.jboss.wsf.common.injection.finders.ResourceMethodFinder;
import org.jboss.wsf.common.reflection.ClassProcessor;
import org.jboss.wsf.spi.metadata.injection.InjectionMetaData;
import org.jboss.wsf.spi.metadata.injection.InjectionsMetaData;

/**
* An injection helper class for <b>javax.*</b> annotations.
*
* @author <a href="mailto:richard.opalka@jboss.org">Richard Opalka</a>
*/
public final class InjectionHelper
{

   private static final Logger LOG = Logger.getLogger(InjectionHelper.class);

   private static final ClassProcessor<Method> POST_CONSTRUCT_METHOD_FINDER = new PostConstructMethodFinder();
   private static final ClassProcessor<Method> PRE_DESTROY_METHOD_FINDER = new PreDestroyMethodFinder();
   private static final ClassProcessor<Method> RESOURCE_METHOD_FINDER = new ResourceMethodFinder(WebServiceContext.class, false);
   private static final ClassProcessor<Field> RESOURCE_FIELD_FINDER = new ResourceFieldFinder(WebServiceContext.class, false);
   private static final ClassProcessor<Method> EJB_METHOD_FINDER = new EJBMethodFinder();
   private static final ClassProcessor<Field> EJB_FIELD_FINDER = new EJBFieldFinder();
   private static final ClassProcessor<Method> WEB_SERVICE_CONTEXT_METHOD_FINDER = new ResourceMethodFinder(WebServiceContext.class, true);
   private static final ClassProcessor<Field> WEB_SERVICE_CONTEXT_FIELD_FINDER = new ResourceFieldFinder(WebServiceContext.class, true);

   /**
    * Forbidden constructor.
    */
   private InjectionHelper()
   {
      super();
   }

   /**
    * The resource annotations mark resources that are needed by the application. These annotations may be applied
    * to an application component class, or to fields or methods of the component class. When the annotation is
    * applied to a field or method, the container will inject an instance of the requested resource into the
    * application component when the component is initialized. If the annotation is applied to the component class,
    * the annotation declares a resource that the application will look up at runtime.
    *
    * This method handles the following injection types:
    * <ul>
    *   <li>Descriptor specified injections</li>
    *   <li>@Resource annotated methods and fields</li>
    *   <li>@EJB annotated methods and fields</li>
    * </ul>
    *
    * @param instance to inject resources on
    * @param injections injection metadata
    * @see org.jboss.wsf.spi.metadata.injection.InjectionsMetaData
    * @see javax.annotation.Resource
    * @see javax.ejb.EJB
    */
   public static void injectResources(final Object instance, final InjectionsMetaData injections, final Context ctx)
   {
      if (instance == null)
         throw new IllegalArgumentException("Object instance cannot be null");

      if (injections == null)
         return;
     
      if (ctx == null)
         return;
     
      // inject descriptor driven annotations
      injectDescriptorAnnotatedAccessibleObjects(instance, injections, ctx);

      // inject @Resource annotated methods and fields
      injectResourceAnnotatedAccessibleObjects(instance, injections, ctx);

      // inject @EJB annotated methods and fields
      injectEJBAnnotatedAccessibleObjects(instance, injections);
   }

   /**
    * Injects @Resource annotated accessible objects referencing WebServiceContext.
    *
    * @param instance to operate on
    * @param ctx current web service context
    */
   public static void injectWebServiceContext(final Object instance, final WebServiceContext ctx)
   {
      final Class<?> instanceClass = instance.getClass();

      // inject @Resource annotated methods accepting WebServiceContext parameter
      Collection<Method> resourceAnnotatedMethods = WEB_SERVICE_CONTEXT_METHOD_FINDER.process(instanceClass);
      for(Method method : resourceAnnotatedMethods)
      {
         try
         {
            invokeMethod(instance, method, new Object[] {ctx});
         }
         catch (Exception e)
         {
            final String message = "Cannot inject @Resource annotated method: " + method;
            InjectionException.rethrow(message, e);
         }
      }

      // inject @Resource annotated fields of WebServiceContext type
      final Collection<Field> resourceAnnotatedFields = WEB_SERVICE_CONTEXT_FIELD_FINDER.process(instanceClass);
      for (Field field : resourceAnnotatedFields)
      {
         try
         {
            setField(instance, field, ctx);
         }
         catch (Exception e)
         {
            final String message = "Cannot inject @Resource annotated field: " + field;
            InjectionException.rethrow(message, e);
         }
      }
   }

   /**
    * Calls @PostConstruct annotated method if exists.
    *
    * @param instance to invoke @PostConstruct annotated method on
    * @see org.jboss.wsf.common.injection.finders.PostConstructMethodFinder
    * @see javax.annotation.PostConstruct
    */
   public static void callPostConstructMethod(final Object instance)
   {
      if (instance == null)
         throw new IllegalArgumentException("Object instance cannot be null");

      final Collection<Method> methods = POST_CONSTRUCT_METHOD_FINDER.process(instance.getClass());

      if (methods.size() > 0)
      {
         final Method method = methods.iterator().next();
         LOG.debug("Calling @PostConstruct annotated method: " + method);
         try
         {
            invokeMethod(instance, method, null);
         }
         catch (Exception e)
         {
            final String message = "Calling of @PostConstruct annotated method failed: " + method;
            InjectionException.rethrow(message, e);
         }
      }
   }

   /**
    * Calls @PreDestroy annotated method if exists.
    *
    * @param instance to invoke @PreDestroy annotated method on
    * @see org.jboss.wsf.common.injection.finders.PreDestroyMethodFinder
    * @see javax.annotation.PreDestroy
    */
   public static void callPreDestroyMethod(final Object instance)
   {
      if (instance == null)
         throw new IllegalArgumentException("Object instance cannot be null");

      final Collection<Method> methods = PRE_DESTROY_METHOD_FINDER.process(instance.getClass());

      if (methods.size() > 0)
      {
         final Method method = methods.iterator().next();
         LOG.debug("Calling @PreDestroy annotated method: " + method);
         try
         {
            invokeMethod(instance, method, null);
         }
         catch (Exception e)
         {
            final String message = "Calling of @PreDestroy annotated method failed: " + method;
            InjectionException.rethrow(message, e);
         }
      }
   }

   /**
    * Performs descriptor driven injections.
    *
    * @param instance to operate on
    * @param injections injections metadata
    * @param ctx JNDI context
    */
   private static void injectDescriptorAnnotatedAccessibleObjects(final Object instance, final InjectionsMetaData injections, final Context ctx)
   {
      final Collection<InjectionMetaData> injectionMDs = injections.getInjectionsMetaData(instance.getClass());

      for (InjectionMetaData injectionMD : injectionMDs)
      {

         final Method method = getMethod(injectionMD, instance.getClass());
         if (method != null)
         {
            try
            {
               inject(instance, method, injectionMD.getEnvEntryName(), ctx);
            }
            catch (Exception e)
            {
               final String message = "Cannot inject method (descriptor driven injection): " + injectionMD;
               InjectionException.rethrow(message, e);
            }
         }
         else
         {
            final Field field = getField(injectionMD, instance.getClass());
            if (field != null)
            {
               try
               {
                  inject(instance, field, injectionMD.getEnvEntryName(), ctx);
               }
               catch (Exception e)
               {
                  final String message = "Cannot inject field (descriptor driven injection): " + injectionMD;
                  InjectionException.rethrow(message, e);
               }
            }
            else
            {
               final String message = "Cannot find injection target for: " + injectionMD;
               throw new InjectionException(message);
            }
         }
     
      }
   }

   /**
    * Injects @Resource annotated accessible objects.
    *
    * @param instance to operate on
    * @param injections injections meta data
    * @param ctx JNDI context
    * @see org.jboss.wsf.common.injection.finders.ResourceFieldFinder
    * @see org.jboss.wsf.common.injection.finders.ResourceMethodFinder
    * @see javax.annotation.Resource
    */
   private static void injectResourceAnnotatedAccessibleObjects(final Object instance, final InjectionsMetaData injections, final Context ctx)
   {
      final Collection<Field> resourceAnnotatedFields = RESOURCE_FIELD_FINDER.process(instance.getClass());
      final Collection<Method> resourceAnnotatedMethods = RESOURCE_METHOD_FINDER.process(instance.getClass());

      // Inject @Resource annotated fields
      for (Field field : resourceAnnotatedFields)
      {
         try
         {
            final String jndiName = injections.getResolver(Resource.class).resolve(field);
            inject(instance, field, jndiName, ctx);
         }
         catch (Exception e)
         {
            final String message = "Cannot inject field annotated with @Resource annotation: " + field;
            InjectionException.rethrow(message, e);
         }
      }

      // Inject @Resource annotated methods
      for(Method method : resourceAnnotatedMethods)
      {
         try
         {
            final String jndiName = injections.getResolver(Resource.class).resolve(method);
            inject(instance, method, jndiName, ctx);
         }
         catch (Exception e)
         {
            final String message = "Cannot inject method annotated with @Resource annotation: " + method;
            InjectionException.rethrow(message, e);
         }
      }
   }

   /**
    * Injects @EJB annotated accessible objects.
    *
    * @param instance to operate on
    * @param injections injections meta data
    * @param ctx JNDI context
    * @see org.jboss.wsf.common.injection.finders.EJBFieldFinder
    * @see org.jboss.wsf.common.injection.finders.EJBMethodFinder
    * @see javax.ejb.EJB
    */
   private static void injectEJBAnnotatedAccessibleObjects(final Object instance, final InjectionsMetaData injections)
   {
      final Collection<Field> ejbAnnotatedFields = EJB_FIELD_FINDER.process(instance.getClass());
      final Collection<Method> ejbAnnotatedMethods = EJB_METHOD_FINDER.process(instance.getClass());
      final Context ctx = InjectionHelper.getDefaultContext();

      // Inject @EJB annotated fields
      for (Field field : ejbAnnotatedFields)
      {
         try
         {
            final String jndiName = injections.getResolver(EJB.class).resolve(field);
            inject(instance, field, jndiName, ctx);
         }
         catch (Exception e)
         {
            final String message = "Cannot inject field annotated with @EJB annotation: " + field;
            InjectionException.rethrow(message, e);
         }
      }

      // Inject @EJB annotated methods
      for(Method method : ejbAnnotatedMethods)
      {
         try
         {
            final String jndiName = injections.getResolver(EJB.class).resolve(method);
            inject(instance, method, jndiName, ctx);
         }
         catch (Exception e)
         {
            final String message = "Cannot inject method annotated with @EJB annotation: " + method;
            InjectionException.rethrow(message, e);
         }
      }
   }

   /**
    * Injects method.
    *
    * @param instance to invoke method on
    * @param method to invoke
    * @param resourceName resource name
    * @param cxt JNDI context
    */
   private static void inject(final Object instance, final Method method, final String jndiName, final Context ctx)
   {
      final Object value = lookup(jndiName, ctx);
      LOG.debug("Injecting method: " + method);
      invokeMethod(instance, method, new Object[] {value});
   }

   /**
    * Injects field.
    *
    * @param field to set
    * @param instance to modify field on
    * @param resourceName resource name
    * @param cxt JNDI context
    */
   private static void inject(final Object instance, final Field field, final String jndiName, final Context ctx)
   {
      final Object value = lookup(jndiName, ctx);
      LOG.debug("Injecting field: " + field);
      setField(instance, field, value);
   }

   /**
    * Lookups object in JNDI namespace.
    *
    * @param jndiName jndi name
    * @param ctx context to use
    * @return Object if found
    */
   private static Object lookup(final String jndiName, final Context ctx)
   {
      Object value = null;
      try
      {
         value = ctx.lookup(jndiName);
      }
      catch (NamingException ne)
      {
         final String message = "Resource '" + jndiName + "' not found";
         InjectionException.rethrow(message, ne);
      }

      return value;
   }
  
   /**
    * Invokes method on object with specified arguments.
    *
    * @param instance to invoke method on
    * @param method method to invoke
    * @param args arguments to pass
    */
   private static void invokeMethod(final Object instance, final Method method, final Object[] args)
   {
      final boolean accessability = method.isAccessible();

      try
      {
         method.setAccessible(true);
         method.invoke(instance, args);
      }
      catch (Exception e)
      {
         InjectionException.rethrow(e);
      }
      finally
      {
         method.setAccessible(accessability);
      }
   }

   /**
    * Sets field on object with specified value.
    *
    * @param instance to set field on
    * @param field to set
    * @param value to be set
    */
   private static void setField(final Object instance, final Field field, final Object value)
   {
      final boolean accessability = field.isAccessible();

      try
      {
         field.setAccessible(true);
         field.set(instance, value);
      }
      catch (Exception e)
      {
         InjectionException.rethrow(e);
      }
      finally
      {
         field.setAccessible(accessability);
      }
   }

   /**
    * Returns method that matches the descriptor injection metadata or null if not found.
    *
    * @param injectionMD descriptor injection metadata
    * @param clazz to process
    * @return method that matches the criteria or null if not found
    * @see org.jboss.wsf.common.injection.finders.InjectionMethodFinder
    */
   private static Method getMethod(final InjectionMetaData injectionMD, final Class<?> clazz)
   {
      final Collection<Method> result = new InjectionMethodFinder(injectionMD).process(clazz);

      return result.isEmpty() ? null : result.iterator().next();
   }

   /**
    * Returns field that matches the descriptor injection metadata or null if not found.
    *
    * @param injectionMD descriptor injection metadata
    * @param clazz to process
    * @return field that matches the criteria or null if not found
    * @see org.jboss.wsf.common.injection.finders.InjectionFieldFinder
    */
   private static Field getField(final InjectionMetaData injectionMD, final Class<?> clazz)
   {
      final Collection<Field> result = new InjectionFieldFinder(injectionMD).process(clazz);

      return result.isEmpty() ? null : result.iterator().next();
   }

   /**
    * Returns default JNDI context.
    *
    * @return default JNDI context
    */
   private static Context getDefaultContext()
   {
      Context ctx = null;
     
      try
      {
         ctx = new InitialContext();
      }
      catch (NamingException ne)
      {
         final String message = "Cannot create default JNDI context";
         InjectionException.rethrow(message, ne);
      }
     
      return ctx;
   }

}
TOP

Related Classes of org.jboss.wsf.common.injection.InjectionHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.