Package com.caucho.config.inject

Source Code of com.caucho.config.inject.InjectionTargetImpl$FieldHandlerProgram

/*
* Copyright (c) 1998-2010 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source 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, or any warranty
* of NON-INFRINGEMENT.  See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
*   Free Software Foundation, Inc.
*   59 Temple Place, Suite 330
*   Boston, MA 02111-1307  USA
*
* @author Scott Ferguson
*/

package com.caucho.config.inject;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.decorator.Delegate;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.CreationException;
import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.AnnotatedConstructor;
import javax.enterprise.inject.spi.AnnotatedField;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedParameter;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.enterprise.inject.spi.InjectionTarget;
import javax.inject.Inject;
import javax.inject.Qualifier;
import javax.interceptor.InvocationContext;

import com.caucho.config.ConfigException;
import com.caucho.config.SerializeHandle;
import com.caucho.config.bytecode.SerializationAdapter;
import com.caucho.config.gen.ApiClass;
import com.caucho.config.gen.BeanInjectionTarget;
import com.caucho.config.gen.PojoBean;
import com.caucho.config.j2ee.PostConstructProgram;
import com.caucho.config.j2ee.PreDestroyInject;
import com.caucho.config.program.Arg;
import com.caucho.config.program.BeanArg;
import com.caucho.config.program.ConfigProgram;
import com.caucho.config.program.ValueArg;
import com.caucho.config.reflect.AnnotatedTypeImpl;
import com.caucho.inject.Module;
import com.caucho.util.L10N;

/**
* SimpleBean represents a POJO Java bean registered as a WebBean.
*/
@Module
public class InjectionTargetImpl<X> extends AbstractIntrospectedBean<X>
  implements InjectionTarget<X>
{
  private static final L10N L = new L10N(InjectionTargetImpl.class);
  private static final Logger log
    = Logger.getLogger(InjectionTargetImpl.class.getName());

  private static final Object []NULL_ARGS = new Object[0];

  private boolean _isBound;

  private Class<X> _instanceClass;

  private AnnotatedType<X> _beanType;

  private Set<Annotation> _interceptorBindings;

  private AnnotatedConstructor<X> _beanCtor;
  private Constructor<X> _javaCtor;
  private Arg []_args;
 
  private boolean _isGenerateInterception = true;

  private ConfigProgram []_newArgs;
  private ConfigProgram []_injectProgram;
  private ConfigProgram []_initProgram;
  private ConfigProgram []_destroyProgram;

  private Set<InjectionPoint> _injectionPointSet
    = new HashSet<InjectionPoint>();

  private ArrayList<ConfigProgram> _injectProgramList
    = new ArrayList<ConfigProgram>();
 
  public InjectionTargetImpl(InjectManager beanManager,
                             AnnotatedType<X> beanType)
  {
    super(beanManager, beanType.getBaseType(), beanType);

    _beanType = beanType;

    /*
    if (beanType.getType() instanceof Class)
      validateType((Class) beanType.getType());
    */
  }

  public AnnotatedType<X> getAnnotatedType()
  {
    return _beanType;
  }

  /**
   * Checks for validity for classpath scanning.
   */
  public static boolean isValid(Class<?> type)
  {
    if (type.isInterface())
      return false;

    if (type.getTypeParameters() != null
        && type.getTypeParameters().length > 0) {
      return false;
    }

    if (! isValidConstructor(type))
      return false;

    return true;
  }

  public static boolean isValidConstructor(Class<?> type)
  {
    for (Constructor<?> ctor : type.getDeclaredConstructors()) {
      if (ctor.getParameterTypes().length == 0)
        return true;

      if (ctor.isAnnotationPresent(Inject.class))
        return true;
    }

    return false;
  }

  public void setConstructor(Constructor ctor)
  {
    // XXX: handled differently now
    throw new IllegalStateException();
    // _ctor = ctor;
  }

  private Class<?> getInstanceClass()
  {
    return _instanceClass;
  }
 
  public void setGenerateInterception(boolean isEnable)
  {
    _isGenerateInterception = isEnable;
  }

  /**
   * Sets the init program.
   */
  public void setNewArgs(ArrayList<ConfigProgram> args)
  {
    // XXX: handled differently
    if (args != null) {
      _newArgs = new ConfigProgram[args.size()];
      args.toArray(_newArgs);
    }
  }

  public Set<Annotation> getInterceptorBindings()
  {
    return _interceptorBindings;
  }

  private static boolean isAnnotationPresent(Annotation []annotations, Class<?> type)
  {
    for (Annotation ann : annotations) {
      if (ann.annotationType().equals(type))
        return true;
    }

    return false;
  }

  @Override
  public X produce(CreationalContext<X> contextEnv)
  {
    try {
      if (! _isBound)
        bind();

      CreationalContextImpl<X> env = null;
     
      if (contextEnv instanceof CreationalContextImpl<?>)
        env = (CreationalContextImpl<X>) contextEnv;

      if (_args == null)
        throw new IllegalStateException(L.l("Can't instantiate bean because it is not a valid ManagedBean: '{0}'", toString()));

      Object []args;
      int size = _args.length;
      if (size > 0) {
        args = new Object[size];

        for (int i = 0; i < size; i++) {
          args[i] = _args[i].eval(env);
        }
      }
      else
        args = NULL_ARGS;

      Object value = _javaCtor.newInstance(args);

      if (value instanceof HandleAware) {
        SerializationAdapter.setHandle(value, getHandle());
      }

      return (X) value;
    } catch (RuntimeException e) {
      throw e;
    } catch (InvocationTargetException e) {
      if (e.getCause() instanceof RuntimeException)
        throw (RuntimeException) e.getCause();
      else
        throw new CreationException(e.getCause());
    } catch (Exception e) {
      throw new CreationException(e);
    }
  }

  protected Object getHandle()
  {
    return new SingletonHandle(getId());
  }

  public void inject(X instance, CreationalContext<X> env)
  {
    try {
      if (! _isBound)
        bind();

      for (ConfigProgram program : _injectProgram) {
        program.inject(instance, env);
      }
    } catch (RuntimeException e) {
      throw e;
    } catch (Exception e) {
      throw new CreationException(e);
    }
  }

  public void postConstruct(X instance)
  {
    try {
      if (! _isBound)
        bind();

      CreationalContext<X> env = null;

      for (ConfigProgram program : _initProgram) {
        program.inject(instance, env);
      }

      // server/4750
      if (instance instanceof BeanInjectionTarget) {
        BeanInjectionTarget bean = (BeanInjectionTarget) instance;
        bean.__caucho_postConstruct();
      }
    } catch (RuntimeException e) {
      throw e;
      /*
    } catch (InvocationTargetException e) {
      throw ConfigException.create(e.getCause());
      */
    } catch (Exception e) {
      throw new CreationException(e);
    }
  }

  public void dispose(X instance)
  {
  }

  /**
   * Binds parameters
   */
  public void bind()
  {
    synchronized (this) {
      if (_isBound)
        return;
      _isBound = true;

      Class<?> cl = getTargetClass();

      HashMap<Method,Annotation[]> methodMap
        = new HashMap<Method,Annotation[]>();

      ArrayList<ConfigProgram> initList = new ArrayList<ConfigProgram>();
      introspectInit(initList, cl, methodMap);
      _initProgram = new ConfigProgram[initList.size()];
      initList.toArray(_initProgram);

      ArrayList<ConfigProgram> destroyList = new ArrayList<ConfigProgram>();
      introspectDestroy(destroyList, cl);
      _destroyProgram = new ConfigProgram[destroyList.size()];
      destroyList.toArray(_destroyProgram);

      if (_beanCtor == null) {
        // XXX:
        AnnotatedType beanType = _beanType;
        if (beanType != null)
          beanType = new AnnotatedTypeImpl(cl, cl);

        introspectConstructor(beanType);
      }

      // introspectObservers(getTargetClass());

      Class<X> instanceClass = null;

      if (_isGenerateInterception) {
        if (! _beanType.isAnnotationPresent(javax.interceptor.Interceptor.class)
            && ! _beanType.isAnnotationPresent(javax.decorator.Decorator.class)) {
          ApiClass apiClass = new ApiClass(_beanType, true);

          PojoBean bean = new PojoBean(apiClass);
          bean.introspect();

          instanceClass = (Class<X>) bean.generateClass();
        }

        if (instanceClass == getTargetClass() && isSerializeHandle()) {
          instanceClass = SerializationAdapter.gen(instanceClass);
        }
      }

      if (instanceClass != null && instanceClass != _instanceClass) {
        try {
          if (_javaCtor != null) {
            _javaCtor = instanceClass.getConstructor(_javaCtor.getParameterTypes());
            _javaCtor.setAccessible(true);
          }

          _instanceClass = instanceClass;
        } catch (Exception e) {
          // server/2423
          log.log(Level.FINE, e.toString(), e);
          // throw ConfigException.create(e);
        }
      }
    }
  }

  public static void
    introspectInit(ArrayList<ConfigProgram> initList,
                   Class<?> type,
                   HashMap<Method,Annotation[]> methodAnnotationMap)
    throws ConfigException
  {
    if (type == null || type.equals(Object.class))
      return;

    introspectInit(initList, type.getSuperclass(), methodAnnotationMap);

    for (Method method : type.getDeclaredMethods()) {
      Annotation []annList = null;

      if (methodAnnotationMap != null)
        annList = methodAnnotationMap.get(method);

      if (annList == null)
        annList = method.getAnnotations();

      if (! isAnnotationPresent(annList, PostConstruct.class)) {
        // && ! isAnnotationPresent(annList, Inject.class)) {
        continue;
      }

      if (method.getParameterTypes().length == 1
          && InvocationContext.class.equals(method.getParameterTypes()[0]))
        continue;

      if (isAnnotationPresent(annList, PostConstruct.class)
          && method.getParameterTypes().length != 0) {
          throw new ConfigException(location(method)
                                    + L.l("{0}: @PostConstruct is requires zero arguments"));
      }

      PostConstructProgram initProgram
        = new PostConstructProgram(method);

      if (! initList.contains(initProgram))
        initList.add(initProgram);
    }
  }

  private void
    introspectDestroy(ArrayList<ConfigProgram> destroyList, Class<?> type)
    throws ConfigException
  {
    if (type == null || type.equals(Object.class))
      return;

    introspectDestroy(destroyList, type.getSuperclass());

    for (Method method : type.getDeclaredMethods()) {
      if (method.isAnnotationPresent(PreDestroy.class)) {
        Class<?> []types = method.getParameterTypes();

        if (types.length == 0) {
        }
        else if (types.length == 1 && types[0].equals(InvocationContext.class)) {
          // XXX:
          continue;
        }
        else
          throw new ConfigException(location(method)
                                    + L.l("@PreDestroy is requires zero arguments"));

        PreDestroyInject destroyProgram
          = new PreDestroyInject(method);

        if (! destroyList.contains(destroyProgram))
          destroyList.add(destroyProgram);
      }
    }
  }

  private static String location(Method method)
  {
    String className = method.getDeclaringClass().getName();

    return className + "." + method.getName() + ": ";
  }

  private boolean isSerializeHandle()
  {
    return getAnnotated().isAnnotationPresent(SerializeHandle.class);
  }

  /**
   * Call pre-destroy
   */
  public void preDestroy(X instance)
  {
    try {
      if (!_isBound)
        bind();

      CreationalContext<X> env = null;

      for (ConfigProgram program : _destroyProgram) {
        program.inject(instance, env);
      }
    }
    catch (RuntimeException e) {
      throw e;
    }
    catch (Exception e) {
      throw new CreationException(e);
    }
  }

  /**
   * Call pre-destroy
   */
  /*
  @Override
  public void destroy(T instance)
  {

  }
  */

  /**
   * Returns the injection points.
   */
  @Override
  public Set<InjectionPoint> getInjectionPoints()
  {
    return _injectionPointSet;
  }

  //
  // introspection
  //

  public void introspect()
  {
    super.introspect();

    introspect(_beanType);
  }

  @Override
  protected Annotated getIntrospectedAnnotated()
  {
    return _beanType;
  }

  /**
   * Called for implicit introspection.
   */
  public void introspect(AnnotatedType<X> beanType)
  {
    Class<X> cl = (Class<X>) getIntrospectionClass();
    introspectConstructor(beanType);
    //introspectBindings(beanType);
    //introspectName(beanType);

    introspectInject(beanType);

    //introspectProduces(beanType);

    //introspectObservers(beanType);

    //introspectMBean();

    _injectProgram = new ConfigProgram[_injectProgramList.size()];
    _injectProgramList.toArray(_injectProgram);
  }

  /**
   * Introspects the constructor
   */
  protected void introspectConstructor(AnnotatedType<X> beanType)
  {
    if (_beanCtor != null)
      return;

    // XXX: may need to modify BeanFactory
    if (beanType.getJavaClass().isInterface())
      return;

    try {
      /*
      Class cl = getInstanceClass();

      if (cl == null)
        cl = getTargetClass();
      */

      AnnotatedConstructor<X> best = null;
      AnnotatedConstructor<X> second = null;

      for (AnnotatedConstructor<X> ctor : beanType.getConstructors()) {
        if (_newArgs != null
            && ctor.getParameters().size() != _newArgs.length) {
          continue;
        }
        else if (best == null) {
          best = ctor;
        }
        else if (hasQualifierAnnotation(ctor)) {
          if (best != null && hasQualifierAnnotation(best))
            throw new ConfigException(L.l("'{0}' can't have two constructors marked by @Inject or by a @Qualifier, because the Java Injection BeanManager can't tell which one to use.",
                                          beanType.getJavaClass().getName()));
          best = ctor;
          second = null;
        }
        else if (ctor.getParameters().size() == 0) {
          best = ctor;
        }
        else if (best.getParameters().size() == 0) {
        }
        else if (ctor.getParameters().size() == 1
                 && ctor.getParameters().get(0).equals(String.class)) {
          second = best;
          best = ctor;
        }
      }

      /*
      if (best == null)
        best = cl.getConstructor(new Class[0]);
      */

      if (best == null) {
        throw new ConfigException(L.l("{0}: no constructor found while introspecting bean for Java Injection",
                                      beanType.getJavaClass().getName()));
      }

      if (second == null) {
      }
      else if (beanType.getJavaClass().getName().startsWith("java.lang")
               && best.getParameters().size() == 1
               && best.getParameters().get(0).equals(String.class)) {
        log.fine(L.l("{0}: WebBean does not have a unique constructor, choosing String-arg constructor",
                     beanType.getJavaClass().getName()));
      }
      else
        throw new ConfigException(L.l("{0}: Bean does not have a unique constructor.  One constructor must be marked with @Inject or have a qualifier annotation.",
                                      beanType.getJavaClass().getName()));

      _beanCtor = best;
      _javaCtor = _beanCtor.getJavaMember();
      _javaCtor.setAccessible(true);

      _args = introspectArguments(_beanCtor.getParameters());
    } catch (RuntimeException e) {
      throw e;
    } catch (Exception e) {
      throw ConfigException.create(e);
    }
  }

  protected Arg<?> []introspectArguments(List<AnnotatedParameter<X>> params)
  {
    Arg<?> []args = new Arg[params.size()];

    for (int i = 0; i < args.length; i++) {
      AnnotatedParameter<?> param = params.get(i);

      Annotation []qualifiers = getQualifiers(param);

      if (qualifiers.length > 0)
        args[i] = new BeanArg<X>(param.getBaseType(), qualifiers);
      else
        args[i] = new ValueArg<X>(param.getBaseType());
    }

    return args;
  }

  private Annotation []getQualifiers(Annotated annotated)
  {
    ArrayList<Annotation> qualifierList = new ArrayList<Annotation>();

    for (Annotation ann : annotated.getAnnotations()) {
      if (ann.annotationType().isAnnotationPresent(Qualifier.class)) {
        qualifierList.add(ann);
      }
    }

    if (qualifierList.size() == 0)
      qualifierList.add(CurrentLiteral.CURRENT);

    Annotation []qualifiers = new Annotation[qualifierList.size()];
    qualifierList.toArray(qualifiers);

    return qualifiers;
  }

  private void introspectInject(AnnotatedType<?> type)
  {
    // configureClassResources(injectList, type);

    for (AnnotatedField<?> field : type.getFields()) {
      if (field.getAnnotations().size() == 0)
        continue;

      if (field.isAnnotationPresent(Delegate.class))
        continue;
      else if (hasQualifierAnnotation(field)) {
        // boolean isOptional = isQualifierOptional(field);

        InjectionPoint ij = new InjectionPointImpl(getBeanManager(), this, field);

        _injectionPointSet.add(ij);

        _injectProgramList.add(new FieldInjectProgram(field.getJavaMember(), ij));
      }
      else {
        InjectionPointHandler handler
          = getBeanManager().getInjectionPointHandler(field);
       
        if (handler != null) {
          ConfigProgram program = new FieldHandlerProgram(field, handler);
         
          _injectProgramList.add(program);
        }
      }
    }

    for (AnnotatedMethod method : type.getMethods()) {
      if (method.getAnnotations().size() == 0)
        continue;

      if (method.isAnnotationPresent(Inject.class)) {
        // boolean isOptional = isQualifierOptional(field);

        List<AnnotatedParameter> params = method.getParameters();

        InjectionPoint []args = new InjectionPoint[params.size()];

        for (int i = 0; i < args.length; i++) {
          InjectionPoint ij
            = new InjectionPointImpl(getBeanManager(), this, params.get(i));

          _injectionPointSet.add(ij);

          args[i] = ij;
        }

        _injectProgramList.add(new MethodInjectProgram(method.getJavaMember(),
                                                       args));
      }
      else {
        InjectionPointHandler handler
          = getBeanManager().getInjectionPointHandler(method);
       
        if (handler != null) {
          ConfigProgram program = new MethodHandlerProgram(method, handler);
         
          _injectProgramList.add(program);
        }
      }
    }

    /*
    for (Method method : type.getDeclaredMethods()) {
      String fieldName = method.getName();
      Class []param = method.getParameterTypes();

      if (param.length != 1)
        continue;

      introspect(injectList, method);
    }
    */
  }

  private static boolean hasQualifierAnnotation(AnnotatedField field)
  {
    for (Annotation ann : field.getAnnotations()) {
      Class annType = ann.annotationType();

      if (annType.equals(Inject.class))
        return true;
      // XXX: no longer true
      /*
      if (annType.isAnnotationPresent(Qualifier.class))
        return true;
      */
    }

    return false;
  }

  private static boolean isQualifierOptional(AnnotatedField field)
  {
    for (Annotation ann : field.getAnnotations()) {
      Class annType = ann.annotationType();

      if (annType.isAnnotationPresent(Qualifier.class))
        return false;
    }

    return false;
  }

  private static boolean hasQualifierAnnotation(AnnotatedConstructor ctor)
  {
    return ctor.isAnnotationPresent(Inject.class);
  }

  class FieldInjectProgram extends ConfigProgram {
    private final Field _field;
    private final InjectionPoint _ij;

    FieldInjectProgram(Field field, InjectionPoint ij)
    {
      _field = field;
      _field.setAccessible(true);
      _ij = ij;
    }

    @Override
    public <T> void inject(T instance, CreationalContext<T> env)
    {
      try {
        // server/30i1
        InjectManager beanManager = InjectManager.getCurrent();
       
        Object value = beanManager.getInjectableReference(_ij, env);

        _field.set(instance, value);
      } catch (Exception e) {
        throw ConfigException.create(_field, e);
      }
    }
  }

  class MethodInjectProgram extends ConfigProgram {
    private final Method _method;
    private final InjectionPoint []_args;

    MethodInjectProgram(Method method, InjectionPoint []args)
    {
      _method = method;
      _method.setAccessible(true);
      _args = args;
    }

    @Override
    public <T> void inject(T instance, CreationalContext<T> env)
    {
      try {
        Object []args = new Object[_args.length];

        for (int i = 0; i < _args.length; i++)
          args[i] = getBeanManager().getInjectableReference(_args[i], env);

        _method.invoke(instance, args);
      } catch (Exception e) {
        throw ConfigException.create(_method, e);
      }
    }
  }
 
  class FieldHandlerProgram extends ConfigProgram {
    private final AnnotatedField<?> _field;
    private final InjectionPointHandler _handler;
    private ConfigProgram _boundProgram;
   
    FieldHandlerProgram(AnnotatedField<?> field, InjectionPointHandler handler)
    {
      _field = field;
      _handler = handler;
    }
 
    @Override
    public <T> void inject(T instance, CreationalContext<T> env)
    {
      if (_boundProgram == null)
        bind();
     
      _boundProgram.inject(instance, env);
    }
   
    private void bind()
    {
      _boundProgram = _handler.introspectField(_field);
    }
  }
 
  class MethodHandlerProgram extends ConfigProgram {
    private final AnnotatedMethod<?> _method;
    private final InjectionPointHandler _handler;
    private ConfigProgram _boundProgram;
   
    MethodHandlerProgram(AnnotatedMethod<?> method,
                         InjectionPointHandler handler)
    {
      _method = method;
      _handler = handler;
    }
 
    @Override
    public <T> void inject(T instance, CreationalContext<T> env)
    {
      if (_boundProgram == null)
        bind();
     
      _boundProgram.inject(instance, env);
    }
   
    private void bind()
    {
      _boundProgram = _handler.introspectMethod(_method);
    }
  }
}
TOP

Related Classes of com.caucho.config.inject.InjectionTargetImpl$FieldHandlerProgram

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.
'pageview');