Package org.jboss.ejb3

Source Code of org.jboss.ejb3.EJBContainer

/*
* 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.ejb3;

import org.jboss.aop.Advisor;
import org.jboss.aop.Domain;
import org.jboss.aop.MethodInfo;
import org.jboss.aop.advice.AdviceStack;
import org.jboss.aop.advice.Interceptor;
import org.jboss.aop.annotation.AnnotationRepository;
import org.jboss.aop.joinpoint.Joinpoint;
import org.jboss.aop.microcontainer.annotations.DisableAOP;
import org.jboss.aop.util.MethodHashing;
import org.jboss.beans.metadata.api.annotations.Inject;
import org.jboss.ejb.AllowedOperationsAssociation;
import org.jboss.ejb3.annotation.Clustered;
import org.jboss.ejb3.annotation.SecurityDomain;
import org.jboss.ejb3.annotation.defaults.PoolDefaults;
import org.jboss.ejb3.annotation.impl.ApplicationExceptionImpl;
import org.jboss.ejb3.aop.BeanContainer;
import org.jboss.ejb3.cluster.metadata.ClusteredMetaDataBridge;
import org.jboss.ejb3.common.registrar.spi.Ejb3RegistrarLocator;
import org.jboss.ejb3.common.spi.ErrorCodes;
import org.jboss.ejb3.deployers.JBoss5DependencyPolicy;
import org.jboss.ejb3.effigy.ApplicationExceptionEffigy;
import org.jboss.ejb3.effigy.EnterpriseBeanEffigy;
import org.jboss.ejb3.effigy.common.JBossBeanEffigyInfo;
import org.jboss.ejb3.effigy.spi.BeanEffigyFactory;
import org.jboss.ejb3.injection.InjectionInvocation;
import org.jboss.ejb3.instantiator.impl.Ejb31SpecBeanInstantiator;
import org.jboss.ejb3.instantiator.spi.BeanInstantiationException;
import org.jboss.ejb3.instantiator.spi.BeanInstantiator;
import org.jboss.ejb3.instantiator.spi.BeanInstantiatorRegistration;
import org.jboss.ejb3.instantiator.spi.InvalidConstructionParamsException;
import org.jboss.ejb3.interceptor.InterceptorInfoRepository;
import org.jboss.ejb3.interceptor.InterceptorInjector;
import org.jboss.ejb3.interceptors.container.ManagedObjectAdvisor;
import org.jboss.ejb3.interceptors.direct.DirectContainer;
import org.jboss.ejb3.interceptors.direct.IndirectContainer;
import org.jboss.ejb3.interceptors.metadata.AdditiveBeanInterceptorMetaDataBridge;
import org.jboss.ejb3.interceptors.metadata.InterceptorComponentMetaDataLoaderFactory;
import org.jboss.ejb3.interceptors.metadata.InterceptorMetaDataBridge;
import org.jboss.ejb3.javaee.JavaEEComponent;
import org.jboss.ejb3.javaee.JavaEEComponentHelper;
import org.jboss.ejb3.javaee.JavaEEModule;
import org.jboss.ejb3.metadata.MetaDataBridge;
import org.jboss.ejb3.metadata.annotation.AnnotationRepositoryToMetaData;
import org.jboss.ejb3.pool.Pool;
import org.jboss.ejb3.pool.PoolFactory;
import org.jboss.ejb3.pool.PoolFactoryRegistry;
import org.jboss.ejb3.proxy.factory.ProxyFactoryHelper;
import org.jboss.ejb3.security.SecurityDomainManager;
import org.jboss.ejb3.security.bridge.RunAsMetaDataBridge;
import org.jboss.ejb3.security.bridge.SecurityDomainMetaDataBridge;
import org.jboss.ejb3.statistics.InvocationStatistics;
import org.jboss.ejb3.timeout.spi.TimeoutMethodCallbackRequirements;
import org.jboss.ejb3.tx.UserTransactionImpl;
import org.jboss.ejb3.tx.metadata.ApplicationExceptionComponentMetaDataLoaderFactory;
import org.jboss.ejb3.tx.metadata.ApplicationExceptionMetaDataBridge;
import org.jboss.ejb3.util.Service;
import org.jboss.ejb3.vfs.spi.VirtualFile;
import org.jboss.injection.DependsHandler;
import org.jboss.injection.EJBHandler;
import org.jboss.injection.EJBInjectionContainer;
import org.jboss.injection.EncInjector;
import org.jboss.injection.ExtendedInjectionContainer;
import org.jboss.injection.InjectionHandler;
import org.jboss.injection.InjectionUtil;
import org.jboss.injection.Injector;
import org.jboss.injection.JndiInjectHandler;
import org.jboss.injection.PersistenceContextHandler;
import org.jboss.injection.PersistenceUnitHandler;
import org.jboss.injection.ResourceHandler;
import org.jboss.injection.WebServiceRefHandler;
import org.jboss.jca.spi.ComponentStack;
import org.jboss.logging.Logger;
import org.jboss.metadata.ejb.jboss.JBossAssemblyDescriptorMetaData;
import org.jboss.metadata.ejb.jboss.JBossEnterpriseBeanMetaData;
import org.jboss.metadata.ejb.jboss.JBossMetaData;
import org.jboss.metadata.ejb.spec.ApplicationExceptionMetaData;
import org.jboss.metadata.ejb.spec.InterceptorMetaData;
import org.jboss.metadata.ejb.spec.InterceptorsMetaData;
import org.jboss.metadata.ejb.spec.MethodParametersMetaData;
import org.jboss.metadata.ejb.spec.NamedMethodMetaData;
import org.jboss.metadata.javaee.spec.Environment;
import org.jboss.metadata.javaee.spec.ServiceReferenceMetaData;
import org.jboss.util.StringPropertyReplacer;
import org.jboss.util.naming.Util;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.ApplicationException;
import javax.ejb.EJBException;
import javax.ejb.EJBHome;
import javax.ejb.EJBLocalHome;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.LinkRef;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
* Comment
*
* @author <a href="mailto:bill@jboss.org">Bill Burke</a>
* @version $Revision: 109294 $
*/
@DisableAOP
public abstract class EJBContainer
   implements Container, IndirectContainer<EJBContainer, DirectContainer<EJBContainer>>,
      EJBInjectionContainer, ExtendedInjectionContainer, JavaEEComponent
{
   private static final Logger log = Logger.getLogger(EJBContainer.class);

   private static TimeoutMethodCallbackRequirements timeoutMethodCallbackRequirements = Service.loadService(TimeoutMethodCallbackRequirements.class);
  
   /**
    * Empty parameter set used to create new EJB3 bean instances
    */
   private static final Object[] BEAN_INSTANCE_CONSTRUCTION_PARAMS = new Object[]{};

   private final String name;
  
   private final BeanContainer beanContainer;
  
   private DirectContainer<EJBContainer> directContainer;

   protected EjbEncFactory encFactory;

   protected Pool pool;

   protected String ejbName;
  
   protected ObjectName objectName;

   protected final String beanClassName;
  
   private final Class<?> beanClass;

   protected final ClassLoader classloader;

   // for performance there is an array.
   protected List<Injector> injectors = new ArrayList<Injector>();

   protected Context enc;

   protected Hashtable initialContextProperties;

   protected Map<String, EncInjector> encInjectors = new HashMap<String, EncInjector>();

   protected JBossEnterpriseBeanMetaData xml;
   protected JBossAssemblyDescriptorMetaData assembly;

   protected Map<String, Map<AccessibleObject, Injector>> encInjections = new HashMap<String, Map<AccessibleObject, Injector>>();

//   protected List<InterceptorInfo> classInterceptors = new ArrayList<InterceptorInfo>();
//
//   protected LinkedHashSet<InterceptorInfo> applicableInterceptors;

   private HashMap<Class<?>, InterceptorInjector> interceptorInjectors = new HashMap<Class<?>, InterceptorInjector>();

   private Ejb3Deployment deployment;
  
   /**
    * Used to construct bean instances
    */
   private BeanInstantiator beanInstantiator;

   private DependencyPolicy dependencyPolicy;

   private String jaccContextId;

   protected InvocationStatistics invokeStats = new InvocationStatistics();
  
   private String partitionName;
  
   private List<Class<?>> businessAndComponentInterfaces;
  
   private ThreadLocalStack<BeanContext<?>> currentBean = new ThreadLocalStack<BeanContext<?>>();
  
   protected boolean reinitialize = false;
  
   /**
    * Metadata based annotation repository
    */
   protected AnnotationRepositoryToMetaData metadataBasedAnnotationRepo;
  
   private static final int TOTAL_PERMITS = Integer.MAX_VALUE;
  
   // To support clean startup/shutdown
   private final Semaphore semaphore = new Semaphore(TOTAL_PERMITS, true);
   private final Lock invocationLock = new SemaphoreLock(this.semaphore);
  
   private final Interceptor[] injectionCallbackStack;
  
   private ComponentStack cachedConnectionManager;
  
   private boolean resurrectMetaData = false;

   private final EnterpriseBeanEffigy effigy;

   /**
    * @param name                  Advisor name
    * @param manager               Domain to get interceptor bindings from
    * @param cl                    the EJB's classloader
    * @param beanClassName
    * @param ejbName
    * @param ctxProperties
    * @param interceptorRepository
    * @param deployment
    * @param beanMetaData           the meta data for this bean or null
    */

   protected EJBContainer(String name, Domain domain, ClassLoader cl,
                       String beanClassName, String ejbName, Hashtable ctxProperties,
                       Ejb3Deployment deployment, JBossEnterpriseBeanMetaData beanMetaData) throws ClassNotFoundException
   {
      assert name != null : "name is null";

      this.name = name;
      this.deployment = deployment;
      this.beanClassName = beanClassName;
      this.classloader = cl;
      this.xml = beanMetaData;

      this.beanClass = classloader.loadClass(beanClassName);

      // We can't type cast the direct container, because we just loaded the beanClass
      // so assuming we have an object is a safe bet.
      this.beanContainer = new BeanContainer(this);

      this.ejbName = ejbName;

      String on = createObjectName(ejbName);
      try
      {
         objectName = new ObjectName(on);
      }
      catch (MalformedObjectNameException e)
      {
         throw new RuntimeException("failed to create object name for: " + on, e);
      }

      // Because interceptors will query back the EJBContainer for annotations
      // we must have set beanContainer first and then do the advisor.
      try
      {
         beanContainer.initialize(ejbName, domain, beanClass, beanMetaData, cl);
      }
      catch(Exception e)
      {
         throw new RuntimeException("failed to initialize bean container ",e);
      }

      //annotations = new AnnotationRepositoryToMetaData(this);

      initialContextProperties = ctxProperties;

      // pull out some info from the deployment (if present)
      if(deployment != null)
      {
         // set the dependency policy
         this.dependencyPolicy = deployment.createDependencyPolicy(this);
      }
     
      Advisor advisor = getAdvisor();
      AdviceStack stack = advisor.getManager().getAdviceStack("InjectionCallbackStack");
      if(stack == null)
         throw new IllegalStateException("EJBTHREE-2020: No InjectionCallbackStack defined for domain " + domain + " of " + this);
      injectionCallbackStack = stack.createInterceptors(advisor, null);

      this.effigy = effigy(classloader, beanMetaData);
   }
  
   /**
    * Create an EJBContainer
    *
    * @param name                  Name for the EJB container
    * @param manager               Domain to get interceptor bindings from
    * @param cl                    the EJB's classloader
    * @param beanClassName  Fully qualified name of the ejb class
    * @param ejbName    The name of the EJB to which this container corresponds
    * @param ctxProperties  Context properties for this bean
    * @param beanMetaData           the meta data for this bean or null
    */

   protected EJBContainer(String name, Domain domain, ClassLoader cl,
                       String beanClassName, String ejbName, Hashtable ctxProperties,
                       JBossEnterpriseBeanMetaData beanMetaData) throws ClassNotFoundException
   {
      this(name, domain, cl, beanClassName, ejbName, ctxProperties, null, beanMetaData);
   }

   private void bindEJBContext()
   {
      try
      {
//         Reference ref = new Reference(EJBContext.class.getName(), EJBContextFactory.class.getName(), null);
//         ref.add(new StringRefAddr("containerGuid", Ejb3Registry.guid(this)));
//         ref.add(new StringRefAddr("containerClusterUid", Ejb3Registry.clusterUid(this)));
//         ref.add(new StringRefAddr("isClustered", Boolean.toString(isClustered())));
         // TODO: a temporary measure until jboss-injection is in place
         LinkRef ref = new LinkRef("java:internal/EJBContext");
         Util.rebind(getEnc(), "EJBContext", ref);
      }
      catch (NamingException e)
      {
         throw new RuntimeException(e);
      }
   }
  
   private void bindORB()
   {
      try
      {
         Util.rebind(getEnc(), "ORB", new LinkRef("java:/JBossCorbaORB"));
      }
      catch(NamingException e)
      {
         throw new RuntimeException(e);
      }
   }
  
   /**
    * Creates a {@link LinkRef} for java:comp/TimerService to
    * an internal jndi name for {@link TimerService}
    * @throws NamingException
    */
   private void bindTimerService() throws NamingException
   {
      // link to java:internal/TimerService (which is setup by
      // org.jboss.ejb3.timerservice.naming.TimerServiceBinder)
      LinkRef timerServiceLinkRef = new LinkRef("java:internal/TimerService");
      // bind to java:comp/TimerService
      Util.rebind(getEnc(), "TimerService", timerServiceLinkRef);
   }
  
   @Deprecated
   public boolean canResolveEJB()
   {
      return deployment.canResolveEJB();
   }
  
   public abstract BeanContext<?> createBeanContext();
  
   public String createObjectName(String ejbName)
   {
      return JavaEEComponentHelper.createObjectName(deployment, ejbName);
   }
  
   /**
    * Do not call, for BeanContainer.
    * @throws IllegalAccessException
    * @throws InstantiationException
    */
   public Object createInterceptor(Class<?> interceptorClass) throws InstantiationException, IllegalAccessException
   {
      Object instance = interceptorClass.newInstance();
      InterceptorInjector interceptorInjector = interceptorInjectors.get(interceptorClass);
      assert interceptorInjector != null : "interceptorInjector not found for " + interceptorClass;
      interceptorInjector.inject(null, instance);
      return instance;
   }
  
   public String createObjectName(String unitName, String ejbName)
   {
      return JavaEEComponentHelper.createObjectName(deployment, unitName, ejbName);
   }
  
   /**
    * Do nothing.
    * @param ctx
    */
   public void destroyBeanContext(org.jboss.ejb3.interceptors.container.BeanContext<?> ctx)
   {
     
   }
  
   private static EnterpriseBeanEffigy effigy(ClassLoader cl, JBossEnterpriseBeanMetaData beanMetaData)
           throws ClassNotFoundException
   {
      JBossBeanEffigyInfo info = new JBossBeanEffigyInfo(cl, beanMetaData);
      return service(BeanEffigyFactory.class).create(info, EnterpriseBeanEffigy.class);
   }

   // TODO: re-evaluate this exposure
   @Deprecated
   public Advisor getAdvisor()
   {
      return beanContainer._getAdvisor();
   }

   /*
    * TODO: re-evalute this exposure
    */
   @Deprecated
   public AnnotationRepository getAnnotations()
   {
      return beanContainer.getAnnotationRepository();
   }

   public ApplicationException getApplicationException(Class<?> exceptionType, Method invokedMethod)
   {
      ApplicationExceptionEffigy appEx = effigy.getApplicationException(exceptionType);
      if(appEx != null)
      {
         if(appEx.isInherited() || appEx.getExceptionClass().equals(exceptionType))
            return new ApplicationExceptionImpl(appEx.isRollback());
         else
            return null;
      }
     
      Class[] exceptionTypes = invokedMethod.getExceptionTypes();
      for (Class exceptionClass : exceptionTypes)
      {
         if (exceptionClass.isAssignableFrom(exceptionType.getClass()))
            return new ApplicationExceptionImpl(false);
      }

      return null;
   }
  
   protected BeanContainer getBeanContainer()
   {
      return beanContainer;
   }
  
   /**
    *
    * @return   the bean class of this container
    * @deprecated   use getBeanClass
    */
   public Class<?> getClazz()
   {
      return getBeanClass();
   }

   protected EnterpriseBeanEffigy getEffigy()
   {
      return effigy;
   }

   @SuppressWarnings("unchecked")
   public static <C extends EJBContainer> C getEJBContainer(Advisor advisor)
   {
      try
      {
         return (C) ((ManagedObjectAdvisor<Object, BeanContainer>) advisor).getContainer().getEJBContainer();
      }
      catch(ClassCastException e)
      {
         throw new ClassCastException(e.getMessage() + " using " + advisor);
      }
   }
  
   public String getName()
   {
      return name;
   }
  
   public void pushContext(BeanContext<?> beanContext)
   {
      currentBean.push(beanContext);
   }
  
   /**
    * Makes sure that EJB's ENC is available
    * Delegates to whatever implementation is used to push the ENC of the EJB
    * onto the stack
    *
    */
   protected void pushEnc()
   {
      encFactory.pushEnc(this);
   }

   public BeanContext<?> peekContext()
   {
      BeanContext<?> ctx = currentBean.get();
      assert ctx != null : "ctx is null";
      return ctx;
   }
  
   public BeanContext<?> popContext()
   {
      return currentBean.pop();
   }
  
   /**
    * Pops EJB's ENC from the stack.  Delegates to whatever implementation
    * is used to pop the EJB's ENC from the stock
    *
    */
   protected void popEnc()
   {
      encFactory.popEnc(this);
   }
  
   private static <S> S service(Class<S> service)
   {
      ServiceLoader<S> loader = ServiceLoader.load(service);
      Iterator<S> it = loader.iterator();
      if(!it.hasNext())
         throw new IllegalArgumentException("Unable to find a service for " + service);
      S instance = it.next();
      if(it.hasNext())
         throw new IllegalArgumentException("Multiple services found for " + service + ", " + it);
      return instance;
   }

   public Environment getEnvironmentRefGroup()
   {
      return xml;
   }

   public List<Injector> getInjectors()
   {
      return injectors;
   }


   public String getJaccContextId()
   {
      return jaccContextId;
   }

   /**
    * Do not call, used by BeanContainer.
    * @return
    */
   public List<Method> getVirtualMethods()
   {
      return null;
   }
  
   public void setJaccContextId(String jaccContextId)
   {
      this.jaccContextId = jaccContextId;
   }
  
   public VirtualFile getRootFile()
   {
      return getDeploymentUnit().getRootFile();
   }
  
   /**
    * Return all the business interfaces implemented by this bean.
    *
    * Available after the meta data has been processed.
    *
    * @return   an array of business interfaces or empty if no interface is provided
    */
   public List<Class<?>> getBusinessAndComponentInterfaces()
   {
      if(businessAndComponentInterfaces == null) throw new IllegalStateException("businessAndComponentInterfaces not yet initialized");
      return businessAndComponentInterfaces;
   }
     
   public String getDeploymentQualifiedName()
   {
      return objectName.getCanonicalName();
   }
  
   /**
    * Returns a String identifier for this bean that is qualified by the
    * deployment, and hence should be unique across deployments. Name is of the
    * form "ear=foo.ear,jar=foo.jar,name=Bar", where "Bar" is the value
    * returned by {@link #getEjbName()}. The "ear=foo.ear" portion is ommitted
    * if the bean is not packaged in an ear.
    */
   public String getDeploymentPropertyListString()
   {
      return objectName.getCanonicalKeyPropertyListString();
   }
  
   public DeploymentUnit getDeploymentUnit()
   {
      return deployment.getDeploymentUnit();
   }

   public Ejb3Deployment getDeployment()
   {
      return deployment;
   }

   public DependencyPolicy getDependencyPolicy()
   {
      return dependencyPolicy;
   }

   public boolean isAnnotationPresent(Class<? extends Annotation> annotationType)
   {
      return beanContainer.isAnnotationPresent(annotationType);
   }
  
   /**
    * Is the method a business method of this container.
    *
    * @param businessMethod     the method in question
    * @return   true if so, otherwise false
    */
   public boolean isBusinessMethod(Method businessMethod)
   {
      for(Class<?> businessInterface : getBusinessAndComponentInterfaces())
      {
         for(Method method : businessInterface.getMethods())
         {
            if(isCallable(method, businessMethod))
               return true;
         }
      }
      return false;
   }
  
   /**
    * Can method definition method be used to call method other.
    * For example if the method is defined in an interface it can be used to call a method
    * in a class.
    *
    * @param method
    * @param other
    * @return
    */
   private static boolean isCallable(Method method, Method other)
   {
      if ((method.getDeclaringClass().isAssignableFrom(other.getDeclaringClass())) && (method.getName().equals(other.getName())))
      {
         if (!method.getReturnType().equals(other.getReturnType()))
            return false;
         Class<?>[] params1 = method.getParameterTypes();
         Class<?>[] params2 = other.getParameterTypes();
         if (params1.length == params2.length)
         {
            for (int i = 0; i < params1.length; i++)
            {
               if (params1[i] != params2[i])
                  return false;
            }
            return true;
         }
      }
      return false;
   }  
  
   /**
    * introspects EJB container to find all dependencies
    * and initialize any extra metadata.
    * <p/>
    * This must be called before container is registered with any microcontainer
    *
    * @param dependencyPolicy
    */
   public void processMetadata()
   {
      // XML must be done first so that any annotation overrides are initialized
     
      // todo injection handlers should be pluggable from XML
      Collection<InjectionHandler<Environment>> handlers = this.getInjectionHandlers();
      if(handlers == null)
      {
         handlers = new ArrayList<InjectionHandler<Environment>>();
         handlers.add(new EJBHandler<Environment>());
         handlers.add(new DependsHandler<Environment>());
         handlers.add(new JndiInjectHandler<Environment>());
         handlers.add(new PersistenceContextHandler<Environment>());
         handlers.add(new PersistenceUnitHandler<Environment>());
         handlers.add(new ResourceHandler<Environment>());
         handlers.add(new WebServiceRefHandler<Environment>());
      }

      ClassLoader old = Thread.currentThread().getContextClassLoader();
      Thread.currentThread().setContextClassLoader(classloader);
      try
      {
         // EJB container's XML must be processed before interceptor's as it may override interceptor's references
         for (InjectionHandler<Environment> handler : handlers) handler.loadXml(xml, this);

         Map<AccessibleObject, Injector> tmp = InjectionUtil.processAnnotations(this, handlers, getBeanClass());
         injectors.addAll(tmp.values());

         /*
         initialiseInterceptors();
         */
         for (Class<?> interceptorClass : beanContainer.getInterceptorClasses())
         {
            InterceptorMetaData interceptorMetaData = findInterceptor(interceptorClass);
            if(interceptorMetaData == null)
               continue;
           
            for (InjectionHandler<Environment> handler : handlers)
            {
               handler.loadXml(interceptorMetaData, this);
            }
         }
         for (Class<?> interceptorClass : beanContainer.getInterceptorClasses())
         {
            Map<AccessibleObject, Injector> injections = InjectionUtil.processAnnotations(this, handlers, interceptorClass);
            InterceptorInjector injector = new InterceptorInjector(injections);
            interceptorInjectors.put(interceptorClass, injector);
         }

         // When @WebServiceRef is not used service-ref won't be processed
         // In this case we process them late
         if(xml != null && xml.getServiceReferences() != null)
         {
            for(ServiceReferenceMetaData sref : xml.getServiceReferences())
            {
               // FIXME: fix WS metadata
               /*
               if(!sref.isProcessed())
               {
                  try
                  {
                     String name = sref.getServiceRefName();
                     String encName = "env/" + name;
                     Context encCtx = getEnc();

                     UnifiedVirtualFile vfsRoot = new VirtualFileAdaptor(getRootFile());
                     new ServiceRefDelegate().bindServiceRef(encCtx, encName, vfsRoot, getClassloader(), sref);

                  }
                  catch (Exception e)
                  {
                     log.error("Failed to bind service-ref", e);
                  }
               }
               */
            }
         }
        
         // EJBTHREE-1025
         this.checkForDuplicateLocalAndRemoteInterfaces();
        
         for(Class<?> businessInterface : getBusinessAndComponentInterfaces())
            ((JBoss5DependencyPolicy) getDependencyPolicy()).addSupply(businessInterface);
        
         Class localHomeInterface = ProxyFactoryHelper.getLocalHomeInterface(this);
         if(localHomeInterface != null)
            ((JBoss5DependencyPolicy) getDependencyPolicy()).addSupply(localHomeInterface);
        
         Class remoteHomeInterface = ProxyFactoryHelper.getRemoteHomeInterface(this);
         if(remoteHomeInterface != null)
            ((JBoss5DependencyPolicy) getDependencyPolicy()).addSupply(remoteHomeInterface);
      }
      finally
      {
         Thread.currentThread().setContextClassLoader(old);
      }
   }
  
   protected Collection<InjectionHandler<Environment>> getInjectionHandlers()
   {
      if (this.deployment != null)
      {
         return this.deployment.getHandlers();
      }
      return null;
   }
   /**
    * Ensures that the bean does not implement any one interface as both @Local and @Remote
    *
    * EJBTHREE-1025
    *
    * @throws EJBException If the bean does implements any one interface as both @Local and @Remote
    */
   protected void checkForDuplicateLocalAndRemoteInterfaces() throws EJBException
   {
      // Initialize issue used in Error Message
      String issue = "[" + ErrorCodes.ERROR_CODE_EJBTHREE1025 + "]";

      // Obtain annotations, if found
      Local local = (Local) resolveAnnotation(Local.class);
      Remote remote = (Remote) resolveAnnotation(Remote.class);

      // If either local or remote is unspecified, return safely - there can be no overlap
      if (local == null || remote == null)
      {
         return;
      }

      // Ensure "value" attribute of both local and remote are not blank
      if (local.value().length < 1 && local.value().length < 1)
      {
         throw new EJBException("Cannot designate both " + Local.class.getName() + " and " + Remote.class.getName()
               + " annotations without 'value' attribute on " + this.getEjbName() + ". " + issue);
      }

      // Iterate through local and remote interfaces, ensuring any one interface is not being used for both local and remote exposure
      for (Class<?> localClass : local.value())
      {
         for (Class<?> remoteClass : remote.value())
         {
            if (localClass.equals(remoteClass))
            {
               throw new EJBException("Cannot designate " + localClass.getName() + " as both " + Local.class.getName()
                     + " and " + Remote.class.getName() + " on " + this.getEjbName() + ". " + issue);
            }
         }
      }
   }

   public JBossEnterpriseBeanMetaData getXml()
   {
      return xml;
   }

   public JBossAssemblyDescriptorMetaData getAssemblyDescriptor()
   {
      return assembly;
   }

   // FIXME: remove
   @Deprecated
   public void setAssemblyDescriptor(JBossAssemblyDescriptorMetaData assembly)
   {
      this.assembly = assembly;
   }

   protected abstract List<Class<?>> resolveBusinessInterfaces();
  
   public InterceptorInfoRepository getInterceptorRepository()
   {
      throw new RuntimeException("invalid");
   }
  
   public Map<String, EncInjector> getEncInjectors()
   {
      return encInjectors;
   }

   public ComponentStack getCachedConnectionManager()
   {
      return cachedConnectionManager;
   }
  
   public ClassLoader getClassloader()
   {
      return classloader;
   }

   public InitialContext getInitialContext()
   {
      try
      {
         return InitialContextFactory.getInitialContext(initialContextProperties);
      }
      catch (NamingException e)
      {
         throw new RuntimeException(e);
      }
   }

   public Map<String, Map<AccessibleObject, Injector>> getEncInjections()
   {
      return encInjections;
   }

   public Context getEnc()
   {
      if (enc == null)
      {
         if(encFactory == null)
         {
            // postpone the inevitable
            //ClassLoader cl = AccessController.doPrivileged(currentContextClassLoader());
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            Class<?> interfaces[] = { Context.class };
            InvocationHandler handler = new InvocationHandler() {
               public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
               {
                  try
                  {
                     if(encFactory == null)
                        throw new IllegalStateException("EJBTHREE-2056: EjbEncFactory is null, usage of java:comp is not allowed before CREATE");
                     return method.invoke(encFactory.getEnc(EJBContainer.this), args);
                  }
                  catch(InvocationTargetException e)
                  {
                     throw e.getTargetException();
                  }
               }
            };
            enc = (Context) Proxy.newProxyInstance(cl, interfaces, handler);
         }
         else
            enc = encFactory.getEnc(this);
      }
      return enc;
   }

   public Hashtable getInitialContextProperties()
   {
      return initialContextProperties;
   }

   public ObjectName getObjectName()
   {
      return objectName;
   }

   public String getEjbName()
   {
      return ejbName;
   }

   public String getBeanClassName()
   {
      return beanClassName;
   }

   public Class<?> getBeanClass()
   {
      return beanClass;
   }

   public Pool getPool()
   {
      return pool;
   }
  
   /**
    * Gets the name of the cluster partition with which this container is
    * associated. Not available until <code>EJBContainer.start()</code>
    * is completed.
    *
    * @return the name of the cluster partition with which this container is
    *         associated, or <code>null</code> if the container is not clustered
    */
   public String getPartitionName()
   {
      if (partitionName == null)
         this.findPartitionName();
      return partitionName;
   }

   /**
    * Delegates bean instance construction to the
    * {@link EJBContainer#beanInstantiator}
    * @return
    */
   protected Object construct()
   {
      try
      {
         return beanInstantiator.create(beanClass, BEAN_INSTANCE_CONSTRUCTION_PARAMS);
      }
      catch (final InvalidConstructionParamsException e)
      {
         throw new RuntimeException(e);
      }
      catch (final BeanInstantiationException e)
      {
         throw new RuntimeException(e);
      }
   }
  
   protected void reinitialize()
   {
      // FIXME: is this correct?
      beanContainer.reinitializeAdvisor();
     
      /*
      initClassMetaDataBindingsList();
      adviceBindings.clear();
      doesHaveAspects = false;
      constructorInfos = null;
      rebuildInterceptors();
      */
     
      bindEJBContext();
     
      reinitialize = false;
   }

   public void create() throws Exception
   {
      // Blocking invocations until start()
      this.blockInvocations();

      if(encFactory == null)
      {
         log.debug("EJBTHREE-2056: Failed to get an EjbEncFactory, will create the default.");
         encFactory = new DefaultEjbEncFactory();
      }

      try
      {
         Util.createSubcontext(getEnc(), "env");
      }
      catch (Exception e)
      {
         throw new RuntimeException(e);
      }
      bindORB();
      bindEJBContext();
      // bind the timerservice to java:comp/TimerService
      bindTimerService();
      /*
      initializeClassContainer();
      for (int i = 0; i < constructors.length; i++)
      {
         if (constructors[i].getParameterTypes().length == 0)
         {
            defaultConstructorIndex = i;
            break;
         }
      }
      */
     
      if(log.isDebugEnabled())
         log.debug("Current context class loader is " + Thread.currentThread().getContextClassLoader());
      if(resurrectMetaData)
      {
         processMetadata();
         resurrectMetaData = false;
      }
   }

   /**
    * This should have been final, but ServiceContainer wants to butt in.
    */
   public void start() throws Exception
   {
      this.lockedStart();
     
      // Allow invocations until stop()
      this.allowInvocations();
     
      // Now that invocations are allowed on the containers,
      // let us invoke this callback so that individual
      // containers can do an startup invocations if required
      this.afterStart();
   }
  
   // Everything must be done in start to make sure all dependencies have been satisfied
   protected void lockedStart() throws Exception
   {
      if (reinitialize)
         reinitialize();
      
      initializePool();

      for (EncInjector injector : encInjectors.values())
      {
         injector.inject(this);  
      }
     
      // creating of injector array should come after injection into ENC as an ENC injector
      // may add additional injectors into the injector list.  An example is an extended persistence
      // context which mush be created and added to the SFSB bean context.

      Injector[] injectors2 = injectors.toArray(new Injector[injectors.size()]);
      if (pool != null) pool.setInjectors(injectors2);

//      createCallbackHandler();
     
      // If we're clustered, find our partition name
      findPartitionName();

      if(this.beanInstantiator == null)
      {
         log.warn("EJBTHREE-2046: beanInstantior not set, using default on " + this);
         // TODO: should not introduce an EJB 3.1 dependency
         this.beanInstantiator = new Ejb31SpecBeanInstantiator();
      }
     
      log.info("STARTED EJB: " + beanClass.getName() + " ejbName: " + ejbName);
   }
  
   /**
    * Invoked after all the dependencies on the containers have satisfied and the
    * container is completely started and open for invocations.
    *
    * Containers can use this method as a callback point where they want to do
    * some startup invocations on the container, which requires the container
    * to be open for invocations (ex: restoring timers - see StatelessContainer)
    *
    * @see #start()
    */
   protected void afterStart()
   {
      // do nothing, let the specific containers (ex: StatelessContainer) do anything
      // specific they want to.
   }

   /**
    * This should have been final, but ServiceContainer wants to butt in.
    */
   public void stop() throws Exception
   {
      // Wait for active invocations to complete - and block new invocations
      this.blockInvocations();
     
      this.lockedStop();
   }
  
   protected void lockedStop() throws Exception
   {
      reinitialize = true;
     
      //encFactory.cleanupEnc(this);
     
      if (pool != null)
      {
         pool.destroy();
         pool = null;
      }
     
      log.info("STOPPED EJB: " + beanClass.getName() + " ejbName: " + ejbName);
   }

   public void destroy() throws Exception
   {
      // Once enc is destroyed, the encInjectors are invalid as well.
      injectors = new ArrayList<Injector>();
      encInjectors = new HashMap<String, EncInjector>();
     
      encFactory.cleanupEnc(this);
      enc = null;
      // TODO: clean up BeanContainer?
      //super.cleanup();
     
      /*
       * EJBTHREE-1984: Leave invocations blocked
       */
      // Restore to pre- create() state
      // this.allowInvocations();
     
      // EJBTHREE-1889: make the bean resurrectable
      resurrectMetaData = true;
   }

   @SuppressWarnings("unchecked")
   public <T> T getSecurityManager(Class<T> type)
   {
      try
      {
         InitialContext ctx = getInitialContext();
         SecurityDomain securityAnnotation = (SecurityDomain) resolveAnnotation(SecurityDomain.class);
         if (securityAnnotation != null && securityAnnotation.value().length() > 0)
         {
            return (T) SecurityDomainManager.getSecurityManager(securityAnnotation.value(),ctx);
         }
         return null;
      }
      catch (NamingException e)
      {
         throw new RuntimeException(e);
      }
   }
  
   protected Method getTimeoutCallback(NamedMethodMetaData timeoutMethodMetaData, Class<?> beanClass)
   {
      String methodName = null;
      Class<?>[] timeoutMethodParams = null;
      JBossEnterpriseBeanMetaData metaData = xml;
      if(metaData != null)
      {
         if(timeoutMethodMetaData != null)
         {
            // timeout method name
            methodName = timeoutMethodMetaData.getMethodName();
            // timeout method params
            MethodParametersMetaData methodParams = timeoutMethodMetaData.getMethodParams();
            String[] paramTypes = methodParams == null ? null : methodParams.toArray(new String[methodParams.size()]);
            timeoutMethodParams = this.loadTimeoutMethodParamTypes(beanClass.getClassLoader(), paramTypes);
         }
      }
     
      Method timeoutMethod = timeoutMethodCallbackRequirements.getTimeoutMethod(beanClass, methodName, timeoutMethodParams);
      if(timeoutMethod != null)
         return timeoutMethod;

      // TODO: should not be needed
      // TODO: ServiceContainer does not container correct metadata
     
      if(metaData != null)
      { 
         // TODO: cross cutting concern
         if(metaData.getEjbJarMetaData().isMetadataComplete())
            return null;
      }
     
      for (Method method : beanClass.getMethods())
      {
         if (getAnnotation(Timeout.class, method) != null)
         {
            if (Modifier.isPublic(method.getModifiers()) &&
                  method.getReturnType().equals(Void.TYPE) &&
                  method.getParameterTypes().length == 1 &&
                  method.getParameterTypes()[0].equals(Timer.class))
            {
               // TODO: check for multiples
               log.warn("EJBTHREE-2017: found a timeout method using legacy annotation scan (bug in JBMETA)");
               return method;
            }
            else
            {
               throw new RuntimeException("@Timeout method " + method + " must have signature: void <METHOD>(javax.ejb.Timer timer) (EJB3 18.2.2)");
            }
         }
      }
     
      return null;
   }
  
   /**
    * Loads the classes passed through the <code>paramTypes</code>, using the <code>cl</code> {@link ClassLoader}
    *
    * @param cl {@link ClassLoader} which will be used to load the param types
    * @param paramTypes The fully qualified type names
    * @return
    */
   private Class<?>[] loadTimeoutMethodParamTypes(ClassLoader cl, String[] paramTypes)
   {
      if (paramTypes == null)
      {
         return null;
      }
      // load the method param classes
      List<Class<?>> timeoutMethodParamTypes = new ArrayList<Class<?>>(paramTypes.length);
      for (String paramClassName : paramTypes)
      {
         Class<?> methodParamClass = null;
         try
         {
            methodParamClass = Class.forName(paramClassName, false, cl);
         }
         catch (ClassNotFoundException cnfe)
         {
            throw new RuntimeException("Could not load method param class: " + paramClassName + " of timeout method");
         }
         timeoutMethodParamTypes.add(methodParamClass);
      }
      return timeoutMethodParamTypes.toArray(new Class<?>[paramTypes.length]);
   }
  
   protected void initializePool() throws Exception
   {
      org.jboss.ejb3.annotation.Pool poolAnnotation = getAnnotation(org.jboss.ejb3.annotation.Pool.class);
      if (poolAnnotation == null)
         throw new IllegalStateException("No pool annotation");
      String registeredPoolName = poolAnnotation.value();
      // EJBTHREE-1119
      if(registeredPoolName==null||registeredPoolName.trim().equals(""))
      {
         // Default the Pool Implementation
         registeredPoolName = PoolDefaults.POOL_IMPLEMENTATION_THREADLOCAL;
      }
      int maxSize = poolAnnotation.maxSize();
      long timeout = poolAnnotation.timeout();
      PoolFactoryRegistry registry = deployment.getPoolFactoryRegistry();
      PoolFactory factory = registry.getPoolFactory(registeredPoolName);
      pool = factory.createPool();
      pool.initialize(this, maxSize, timeout);

      resolveInjectors();
      pool.setInjectors(injectors.toArray(new Injector[injectors.size()]));
   }

   /**
    * Note this method is a WIP.
    *
    * In actuality ejb3-interceptors should perform the injection itself,
    * but this requires a rewrite of all injectors.
    */
   public void injectBeanContext(BeanContext<?> beanContext)
   {
      try
      {
         if(injectors == null)
            return;
         Advisor advisor = getAdvisor();
         InjectionInvocation invocation = new InjectionInvocation(beanContext, injectors, injectionCallbackStack);
         invocation.setAdvisor(advisor);
         invocation.setTargetObject(beanContext.getInstance());
         invocation.invokeNext();
      }
      catch(Throwable t)
      {
         if(t instanceof Error)
            throw (Error) t;
         if(t instanceof RuntimeException)
            throw (RuntimeException) t;
         throw new RuntimeException(t);
      }
   }
  
   /**
    * Note that this method is a WIP.
    *
    * @param beanContext
    * @param callbackAnnotationClass    on of PostConstruct, PreDestroy, PostActivate or PrePassivate
    */
   protected void invokeCallback(BeanContext<?> beanContext, Class<? extends Annotation> callbackAnnotationClass)
   {
      // it's the BeanContainer's responsibility to invoke the callback
      // through the correct interceptors. So let's pass the call to the beanContainer
      this.getBeanContainer().invokeCallback(beanContext, callbackAnnotationClass);
   }
  
   public void invokePostConstruct(BeanContext<?> beanContext)
   {
      // FIXME: This is a dirty hack to notify AS EJBTimerService about what's going on
      AllowedOperationsAssociation.pushInMethodFlag(AllowedOperationsAssociation.IN_EJB_CREATE);
      try
      {
         this.pushContext(beanContext);

         invokeCallback(beanContext, PostConstruct.class);
      }
      finally
      {
         this.popContext();
         AllowedOperationsAssociation.popInMethodFlag();
      }
   }
  
   @Deprecated
   public void invokePostConstruct(BeanContext beanContext, Object[] params)
   {
      invokePostConstruct(beanContext);
   }

   public void invokePreDestroy(BeanContext beanContext)
   {
      invokeCallback(beanContext, PreDestroy.class);
   }

   public void invokePostActivate(BeanContext beanContext)
   {
      throw new RuntimeException("PostActivate not implemented for container");
   }

   public void invokePrePassivate(BeanContext beanContext)
   {
      throw new RuntimeException("PrePassivate not implemented for container");
   }

   /*
   public void invokeInit(Object bean, Class[] initParameterTypes,
                          Object[] initParameterValues)
   {
      // do nothing, only useful on a stateful session bean
   }
   */

   public static final String MANAGED_ENTITY_MANAGER_FACTORY = "ManagedEntityManagerFactory";

   public static final String ENTITY_MANAGER_FACTORY = "EntityManagerFactory";

   protected void resolveInjectors() throws Exception
   {
      pushEnc();
      try
      {
         Thread.currentThread().setContextClassLoader(classloader);
         try
         {
            Util.rebind(getEnc(), "UserTransaction", new UserTransactionImpl());
         }
         catch (NamingException e)
         {
            NamingException namingException = new NamingException("Could not bind user transaction for ejb name " + ejbName + " into JNDI under jndiName: " + getEnc().getNameInNamespace() + "/" + "UserTransaction");
            namingException.setRootCause(e);
            throw namingException;
         }
         try
         {
            Util.rebind(getEnc(), "TransactionSynchronizationRegistry", new LinkRef("java:TransactionSynchronizationRegistry"));
            log.debug("Linked java:comp/TransactionSynchronizationRegistry to JNDI name: java:TransactionSynchronizationRegistry");
         }
         catch (NamingException e)
         {
            NamingException namingException = new NamingException("Could not bind TransactionSynchronizationRegistry for ejb name " + ejbName + " into JNDI under jndiName: " + getEnc().getNameInNamespace() + "/" + "TransactionSynchronizationRegistry");
            namingException.setRootCause(e);
            throw namingException;
         }
      }
      finally
      {
         popEnc();
      }
   }

   protected Class[] getHandledCallbacks()
   {
      return new Class[]
              {PostConstruct.class, PreDestroy.class, Timeout.class};
   }

   // TODO: once injection is finalized this method will disappear
   private InterceptorMetaData findInterceptor(Class<?> interceptorClass)
   {
      if(xml == null)
         return null;
      JBossMetaData ejbJarMetaData = xml.getEjbJarMetaData();
      if(ejbJarMetaData == null)
         return null;
      InterceptorsMetaData interceptors = ejbJarMetaData.getInterceptors();
      if(interceptors == null)
         return null;
      for(InterceptorMetaData interceptorMetaData : interceptors)
      {
         if(interceptorMetaData.getInterceptorClass().equals(interceptorClass.getName()))
            return interceptorMetaData;
      }
      return null;
   }
  
   protected void findPartitionName()
   {
      Clustered clustered = (Clustered) getAnnotation(Clustered.class);
      if (clustered == null)
      {
         partitionName = null;
         return;
      }
     
      String value = clustered.partition();
      try
      {
         String replacedValue = StringPropertyReplacer.replaceProperties(value);
         if (value != replacedValue)
         {           
            log.debug("Replacing @Clustered partition attribute " + value + " with " + replacedValue);
            value = replacedValue;
         }
      }
      catch (Exception e)
      {
         log.warn("Unable to replace @Clustered partition attribute " + value +
                  ". Caused by " + e.getClass() + " " + e.getMessage());        
      }
     
      partitionName = value;
   }

   public <T> T getBusinessObject(BeanContext<?> beanContext, Class<T> businessInterface) throws IllegalStateException
   {
      throw new IllegalStateException("Not implemented");
   }

   public Object getInvokedBusinessInterface(BeanContext beanContext) throws IllegalStateException
   {
      throw new IllegalStateException("Not implemented");
   }

   protected Object getInvokedInterface(Method method)
   {
      Remote remoteAnnotation = (Remote) resolveAnnotation(Remote.class);
      if (remoteAnnotation != null)
      {
         Class[] remotes = remoteAnnotation.value();
         for (int i = 0; i < remotes.length; ++i)
         {
            try
            {
               remotes[i].getMethod(method.getName(), method.getParameterTypes());
               return remotes[i];
            }
            catch (NoSuchMethodException e)
            {
            }
         }
      }

      Local localAnnotation = (Local) resolveAnnotation(Local.class);
      if (localAnnotation != null)
      {
         Class[] locals = localAnnotation.value();
         for (int i = 0; i < locals.length; ++i)
         {
            Method[] interfaceMethods = locals[i].getMethods();
            for (int j = 0; j < interfaceMethods.length; ++j)
            {
               if (interfaceMethods[j].equals(method))
                  return locals[i];
            }
         }
      }

      return null;
   }

   // todo these method overrides for aop are for performance reasons
   private Class loadPublicAnnotation(String annotation)
   {
      try
      {
         Class ann = classloader.loadClass(annotation);
         if (!ann.isAnnotation()) return null;
         Retention retention = (Retention) ann.getAnnotation(Retention.class);
         if (retention != null && retention.value() == RetentionPolicy.RUNTIME) return ann;

      }
      catch (ClassNotFoundException ignored)
      {
      }
      return null;
   }

   /*
   @Override
   public boolean hasAnnotation(Class tgt, String annotation)
   {
      if (annotations.hasClassAnnotation(annotation)) return true;
      if (tgt == null) return false;
      try
      {
         Class ann = loadPublicAnnotation(annotation);
         // it is metadata or CLASS annotation
         if (ann == null) return AnnotationElement.isAnyAnnotationPresent(tgt, annotation);
         return tgt.isAnnotationPresent(ann);
      }
      catch (Exception e)
      {
         throw new RuntimeException(e);  //To change body of catch statement use Options | File Templates.
      }
   }


   @Override
   public boolean hasAnnotation(Method m, String annotation)
   {
      if (annotations.hasAnnotation(m, annotation)) return true;
      try
      {
         Class ann = loadPublicAnnotation(annotation);
         // it is metadata or CLASS annotation
         if (ann == null) return AnnotationElement.isAnyAnnotationPresent(m, annotation);
         return m.isAnnotationPresent(ann);
      }
      catch (Exception e)
      {
         throw new RuntimeException(e);  //To change body of catch statement use Options | File Templates.
      }
   }

   @Override
   public boolean hasAnnotation(Field m, String annotation)
   {
      if (annotations.hasAnnotation(m, annotation)) return true;
      try
      {
         Class ann = loadPublicAnnotation(annotation);
         // it is metadata or CLASS annotation
         if (ann == null) return AnnotationElement.isAnyAnnotationPresent(m, annotation);
         return m.isAnnotationPresent(ann);
      }
      catch (Exception e)
      {
         throw new RuntimeException(e);  //To change body of catch statement use Options | File Templates.
      }
   }

   @Override
   public boolean hasAnnotation(Constructor m, String annotation)
   {
      if (annotations.hasAnnotation(m, annotation)) return true;
      try
      {
         Class ann = loadPublicAnnotation(annotation);
         // it is metadata or CLASS annotation
         if (ann == null) return AnnotationElement.isAnyAnnotationPresent(m, annotation);
         return m.isAnnotationPresent(ann);
      }
      catch (Exception e)
      {
         throw new RuntimeException(e);  //To change body of catch statement use Options | File Templates.
      }
   }
   */
  
   public String resolveEJB(String link, Class<?> beanInterface, String mappedName)
   {
      return deployment.resolveEJB(link, beanInterface, mappedName);
   }
  
   public Container resolveEjbContainer(String link, Class businessIntf)
   {
      return deployment.getEjbContainer(link, businessIntf);
   }

   public Container resolveEjbContainer(Class businessIntf) throws NameNotFoundException
   {
      return deployment.getEjbContainer(businessIntf);
   }

   public String resolveMessageDestination(String link)
   {
      return deployment.resolveMessageDestination(link);
   }
  
   public String resolvePersistenceUnitSupplier(String unitName)
   {
      return getDeployment().resolvePersistenceUnitSupplier(unitName);
   }
  
   public <T extends Annotation> T getAnnotation(Class<T> annotationType)
   {
      if (this.getAnnotations().isDisabled(annotationType))
         return null;
     
      return beanContainer.getAnnotation(annotationType);
   }
  
   public <T extends Annotation> T getAnnotation(Class<T> annotationType, Class<?> clazz)
   {
      return beanContainer.getAnnotation(clazz, annotationType);
   }

   public <T extends Annotation> T getAnnotation(Class<T> annotationType, Class<?> clazz, Method method)
   {
      return beanContainer.getAnnotation(annotationType, clazz, method);
   }
  
   public <T extends Annotation> T getAnnotation(Class<T> annotationType, Method method)
   {
      if (this.getAnnotations().isDisabled(method, annotationType))
         return null;
     
      return beanContainer.getAnnotation(annotationType, method);
   }

   public <T extends Annotation> T getAnnotation(Class<T> annotationType, Class<?> clazz, Field field)
   {
      return beanContainer.getAnnotation(annotationType, clazz, field);
   }
  
   public <T extends Annotation> T getAnnotation(Class<T> annotationType, Field field)
   {
      return beanContainer.getAnnotation(annotationType, field);
   }
  
   /**
    * @deprecated use getAnnotation
    */
   @SuppressWarnings("unchecked")
   public Object resolveAnnotation(Class annotationType)
   {
      return getAnnotation(annotationType);
   }
  
   /**
    * @deprecated use getAnnotation
    */
   @SuppressWarnings("unchecked")
   public Object resolveAnnotation(Field field, Class annotationType)
   {
      return getAnnotation(annotationType, field);
   }
  
   /**
    * @deprecated use getAnnotation
    */
   @SuppressWarnings("unchecked")
   public Object resolveAnnotation(Method method, Class annotationType)
   {
      return getAnnotation(annotationType, method);
   }
  
   /**
    * @deprecated this is going to be gone soon
    */
   @SuppressWarnings("unchecked")
   public Object resolveAnnotation(Method m, Class[] annotationChoices)
   {
      Object value = null;
      int i = 0;
      while (value == null && i < annotationChoices.length){
         value = resolveAnnotation(m, annotationChoices[i++]);
      }
     
      return value;
   }

   public String getIdentifier()
   {
      return getEjbName();
   }

   public String getDeploymentDescriptorType()
   {
      return "ejb-jar.xml";
   }

   public String getEjbJndiName(Class businessInterface) throws NameNotFoundException
   {
      return deployment.getEjbJndiName(businessInterface);
   }

   public String getEjbJndiName(String link, Class businessInterface)
   {
      return deployment.getEjbJndiName(link, businessInterface);
   }
  
   public InvocationStatistics getInvokeStats()
   {
      return invokeStats;
   }

   @Deprecated
   protected MethodInfo getMethodInfo(Method method)
   {
      long hash = MethodHashing.calculateHash(method);
      MethodInfo info = getAdvisor().getMethodInfo(hash);
      if (info == null)
      {
         throw new RuntimeException("Could not resolve beanClass method from proxy call: " + method.toString());
      }
      return info;
   }
  
   public boolean isClustered()
   {
      return false;
   }
  
   public JavaEEModule getModule()
   {
      return deployment;
   }

   public void setEjbEncFactory(EjbEncFactory encFactory)
   {
      this.encFactory = encFactory;
   }

   public abstract boolean hasJNDIBinding(String jndiName);
  
   /**
    * After XML processing has been done this allows the container
    * to further initialize the meta data.
    */
   public void instantiated()
   {
      this.businessAndComponentInterfaces = resolveBusinessInterfaces();
     
      // Before we start to process annotations, make sure we also have the ones from interceptors-aop.
      // FIXME: because of the flaked life cycle of an EJBContainer (we add annotations after it's been
      // constructed), we must reinitialize the whole thing.
      beanContainer.reinitializeAdvisor();
   }
  
   @Inject
   public void setCachedConnectionManager(ComponentStack ccm)
   {
      this.cachedConnectionManager = ccm;
   }
  
   public void setDirectContainer(DirectContainer<EJBContainer> container)
   {
      this.directContainer = container;
   }
  
   protected Method getNonBridgeMethod(Method bridgeMethod)
   {
      Class clazz = bridgeMethod.getDeclaringClass();
      Method[] methods = clazz.getMethods();
      for (Method method : methods)
      {
         if (!method.isBridge() && method.getParameterTypes().length == bridgeMethod.getParameterTypes().length)
         {
            return method;
         }
      }
     
      return bridgeMethod;
   }
  
   public Lock getInvocationLock()
   {
      return this.invocationLock;
   }

   // to make sure we have a dependency on the TransactionManager
   // note that the actual tx interceptors don't make use of the injected tm
   @Inject
   public void setTransactionManager(TransactionManager tm)
   {
     
   }
  
   /**
    * Returns {@link AnnotationRepositoryToMetaData} corresponding to this {@link EJBContainer}.
    * The returned {@link AnnotationRepositoryToMetaData} is an implementation of {@link AnnotationRepository}
    * and is capable of resolving annotations from bean metadata through the use of {@link MetaDataBridge}s
    *
    * @return
    */
   public AnnotationRepositoryToMetaData getMetaDataBasedAnnotationRepository()
   {
      if (this.metadataBasedAnnotationRepo == null)
      {
         this.initMetaDataBasedAnnotationRepository();
      }
      return this.metadataBasedAnnotationRepo;
   }
  
   /**
    * Initializes the metadata based annotation repository {@link AnnotationRepositoryToMetaData},
    * by setting up the appropriate metadata bridges.
    * <p>
    *   Individual containers can then override this method to add more metadata bridges to the
    *   metadata based annotation repository.
    * </p>
    * <p>
    *   Sets up metadata bridges for
    *   <ul>
    *       <li>SecurityDomain metadata</li>
    *       <li>RunAs metadata</li>
    *       <li>Clustered metadata</li>
    *       <li>ApplicationException metadata</li>
    *       <li>Various metadata bridges for processing lifecycle callbacks on bean an interceptors</li>
    *   </ul>
    * </p>
    *
    */
   protected void initMetaDataBasedAnnotationRepository()
   {
      this.metadataBasedAnnotationRepo = new AnnotationRepositoryToMetaData(this.beanClass, this.xml, name, this.classloader);
      List<MetaDataBridge<InterceptorMetaData>> interceptorBridges = new ArrayList<MetaDataBridge<InterceptorMetaData>>();
      interceptorBridges.add(new InterceptorMetaDataBridge());
      this.metadataBasedAnnotationRepo.addComponentMetaDataLoaderFactory(new InterceptorComponentMetaDataLoaderFactory(interceptorBridges));
      this.metadataBasedAnnotationRepo.addMetaDataBridge(new AdditiveBeanInterceptorMetaDataBridge(this.beanClass, this.classloader, this.xml));
     
      List<MetaDataBridge<ApplicationExceptionMetaData>> appExceptionBridges = new ArrayList<MetaDataBridge<ApplicationExceptionMetaData>>();
      appExceptionBridges.add(new ApplicationExceptionMetaDataBridge());
      this.metadataBasedAnnotationRepo.addComponentMetaDataLoaderFactory(new ApplicationExceptionComponentMetaDataLoaderFactory(appExceptionBridges));
     
      this.metadataBasedAnnotationRepo.addMetaDataBridge(new RunAsMetaDataBridge());
      //Add a security domain bridge
      this.metadataBasedAnnotationRepo.addMetaDataBridge(new SecurityDomainMetaDataBridge());
      // Ensure that an @Clustered annotation is visible to AOP if the XML says the bean is  clustered.
      this.metadataBasedAnnotationRepo.addMetaDataBridge(new ClusteredMetaDataBridge());
   }
  
   public String toString()
   {
      return getObjectName().getCanonicalName();
   }
  
   private void blockInvocations() throws InterruptedException
   {
      // Allow re-entrance
      if (this.semaphore.tryAcquire())
      {
         try
         {
            // Acquire all remaining permits, blocking invocation lock
            this.semaphore.acquire(TOTAL_PERMITS - 1);
         }
         catch (InterruptedException e)
         {
            this.semaphore.release();
           
            throw e;
         }
      }
   }
  
   private void allowInvocations()
   {
      // Allow re-entrance
      if (!this.semaphore.tryAcquire())
      {
         // Make all permits available to invocation lock
         this.semaphore.release(TOTAL_PERMITS);
      }
      else
      {
         // Release the one we just acquired
         this.semaphore.release();
      }
   }
  
   /**
    * {@link java.util.concurrent.locks.Lock} facade for this container's semaphore
    * @author Paul Ferraro
    */
   private static class SemaphoreLock implements Lock
   {
      private final Semaphore semaphore;
     
      SemaphoreLock(Semaphore semaphore)
      {
         this.semaphore = semaphore;
      }
     
      /**
       * @see java.util.concurrent.locks.Lock#lock()
       */
      public void lock()
      {
         this.semaphore.acquireUninterruptibly();
      }

      /**
       * @see java.util.concurrent.locks.Lock#lockInterruptibly()
       */
      public void lockInterruptibly() throws InterruptedException
      {
         this.semaphore.acquire();
      }

      /**
       * @see java.util.concurrent.locks.Lock#newCondition()
       */
      public Condition newCondition()
      {
         throw new UnsupportedOperationException();
      }

      /**
       * @see java.util.concurrent.locks.Lock#tryLock()
       */
      public boolean tryLock()
      {
         return this.semaphore.tryAcquire();
      }

      /**
       * @see java.util.concurrent.locks.Lock#tryLock(long, java.util.concurrent.TimeUnit)
       */
      public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException
      {
         return this.semaphore.tryAcquire(timeout, unit);
      }

      /**
       * @see java.util.concurrent.locks.Lock#unlock()
       */
      public void unlock()
      {
         this.semaphore.release();
      }
   }
  
   /**
    * {@inheritDoc}
    */
   @Override
   public EJBHome getEJBHome() throws IllegalStateException
   {
      throw new UnsupportedOperationException("NYI");
   }

   /**
    * {@inheritDoc}
    */
   public EJBLocalHome getEJBLocalHome() throws IllegalStateException
   {
      throw new UnsupportedOperationException("NYI");
   }

   /**
    * {@inheritDoc}
    */
   public boolean getRollbackOnly() throws IllegalStateException
   {
      throw new UnsupportedOperationException("NYI");
   }

   /**
    * {@inheritDoc}
    */
   public UserTransaction getUserTransaction() throws IllegalStateException
   {
      throw new UnsupportedOperationException("NYI");
   }

   /**
    * {@inheritDoc}
    */
   public boolean isCallerInRole(Principal callerPrincipal, String roleName) throws IllegalStateException
   {
      throw new UnsupportedOperationException("NYI");
   }

   /**
    * {@inheritDoc}
    */
   public Object lookup(String name) throws IllegalArgumentException
   {
      try
      {
         Object obj = this.getEnc().lookup(name);
         return obj;
      }
      catch (NamingException ne)
      {
         throw new RuntimeException(ne);
      }
   }

   /**
    * {@inheritDoc}
    */
   public void setRollbackOnly() throws IllegalStateException
   {
      throw new UnsupportedOperationException("NYI");
   }
  
   /**
    *
    * @param joinPoint
    * @param interceptorStackName
    * @return
    */
   protected Interceptor[] getInterceptors(Joinpoint joinPoint, String interceptorStackName)
   {
      AdviceStack stack = this.getAdvisor().getManager().getAdviceStack(interceptorStackName);
      if (stack == null)
      {
         log.debug("No AOP interceptor stack with name : " + interceptorStackName + " available for EJB container: " + this);
         return new Interceptor[0];
      }
      List<Interceptor> interceptors = new ArrayList<Interceptor>();
      interceptors.addAll(Arrays.asList(stack.createInterceptors(this.getAdvisor(), joinPoint)));
      return interceptors.toArray(new Interceptor[]{});
   }
  
   protected BeanInstantiator getBeanInstantiator()
   {
      return this.beanInstantiator;
   }

   public void setBeanInstantiator(BeanInstantiator beanInstantiator)
   {
      this.beanInstantiator = beanInstantiator;
   }
}
TOP

Related Classes of org.jboss.ejb3.EJBContainer

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.