Package org.jboss.ejb3.session

Source Code of org.jboss.ejb3.session.SessionSpecContainer

package org.jboss.ejb3.session;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;

import javax.ejb.EJBLocalObject;
import javax.ejb.EJBObject;
import javax.ejb.Handle;

import org.jboss.aop.Advisor;
import org.jboss.aop.Dispatcher;
import org.jboss.aop.Domain;
import org.jboss.aop.MethodInfo;
import org.jboss.aop.advice.Interceptor;
import org.jboss.aop.proxy.ClassProxy;
import org.jboss.aop.util.MethodHashing;
import org.jboss.ejb3.Ejb3Deployment;
import org.jboss.ejb3.Ejb3Registry;
import org.jboss.ejb3.ThreadLocalStack;
import org.jboss.ejb3.annotation.LocalBinding;
import org.jboss.ejb3.annotation.LocalHomeBinding;
import org.jboss.ejb3.annotation.RemoteBinding;
import org.jboss.ejb3.annotation.RemoteBindings;
import org.jboss.ejb3.annotation.RemoteHomeBinding;
import org.jboss.ejb3.common.lang.SerializableMethod;
import org.jboss.ejb3.common.registrar.spi.Ejb3Registrar;
import org.jboss.ejb3.common.registrar.spi.Ejb3RegistrarLocator;
import org.jboss.ejb3.common.registrar.spi.NotBoundException;
import org.jboss.ejb3.proxy.container.InvokableContext;
import org.jboss.ejb3.proxy.handler.session.SessionProxyInvocationHandler;
import org.jboss.ejb3.proxy.handler.session.stateful.StatefulProxyInvocationHandlerBase;
import org.jboss.ejb3.proxy.jndiregistrar.JndiSessionRegistrarBase;
import org.jboss.ejb3.proxy.remoting.SessionSpecRemotingMetadata;
import org.jboss.ejb3.stateful.StatefulContainerInvocation;
import org.jboss.logging.Logger;
import org.jboss.metadata.ejb.jboss.JBossSessionBeanMetaData;
import org.jboss.metadata.ejb.jboss.RemoteBindingMetaData;

/**
* SessionSpecContainer
*
* A SessionContainer with support for Session Beans defined
* specifically by the EJB3 Specification
*
* @author <a href="mailto:andrew.rubinger@jboss.org">ALR</a>
* @version $Revision: $
*/
public abstract class SessionSpecContainer extends SessionContainer implements InvokableContext
{

   // ------------------------------------------------------------------------------||
   // Class Members ----------------------------------------------------------------||
   // ------------------------------------------------------------------------------||

   private static final Logger log = Logger.getLogger(SessionSpecContainer.class);
  
   /**
    * The method invoked upon by the client
    */
   //TODO: Remove when CurrentInvocation is completely sorted out
   @Deprecated
   protected static ThreadLocalStack<SerializableMethod> invokedMethod = new ThreadLocalStack<SerializableMethod>();

   // ------------------------------------------------------------------------------||
   // Instance Members -------------------------------------------------------------||
   // ------------------------------------------------------------------------------||

   private JndiSessionRegistrarBase jndiRegistrar;

   // ------------------------------------------------------------------------------||
   // Constructor ------------------------------------------------------------------||
   // ------------------------------------------------------------------------------||

   public SessionSpecContainer(ClassLoader cl, String beanClassName, String ejbName, Domain domain,
         Hashtable ctxProperties, Ejb3Deployment deployment, JBossSessionBeanMetaData beanMetaData)
         throws ClassNotFoundException
   {
      super(cl, beanClassName, ejbName, domain, ctxProperties, deployment, beanMetaData);
   }

   /**
    * Create a remote proxy (EJBObject) for an enterprise bean identified by id
    *
    * @param id
    * @return
    * @throws Exception
    */
   public Object createProxyRemoteEjb21(String businessInterfaceType) throws Exception
   {
      RemoteBinding binding = this.getRemoteBinding();
      return this.createProxyRemoteEjb21(binding, businessInterfaceType);
   }

   /**
    * Create a remote proxy (EJBObject) for an enterprise bean identified by id on a given binding
    *
    * @param id
    * @param binding
    * @return
    * @throws Exception
    */
   public abstract Object createProxyRemoteEjb21(RemoteBinding binding, String businessInterfaceType) throws Exception;

   /**
    * Create a local proxy (EJBLocalObject) for an enterprise bean identified by id
    *
    * @param id
    * @return
    * @throws Exception
    */
   public Object createProxyLocalEjb21(String businessInterfaceType) throws Exception
   {
      LocalBinding binding = this.getAnnotation(LocalBinding.class);
      return this.createProxyLocalEjb21(binding, businessInterfaceType);
   }

   /**
    * Create a local proxy (EJBLocalObject) for an enterprise bean identified by id, with
    * the specified LocalBinding
    *
    * @param id
    * @return
    * @throws Exception
    */
   public abstract Object createProxyLocalEjb21(LocalBinding binding, String businessInterfaceType) throws Exception;

   /**
    * Invokes the method described by the specified serializable method
    * as called from the specified proxy, using the specified arguments
    *
    * @param proxy The proxy making the invocation
    * @param method The method to be invoked
    * @param args The arguments to the invocation
    * @throws Throwable A possible exception thrown by the invocation
    * @return
    */
   public Object invoke(Object proxy, SerializableMethod method, Object[] args) throws Throwable
   {
      /*
       * Replace the TCL with the CL for this Container
       */
      ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
      Thread.currentThread().setContextClassLoader(this.getClassloader());
     
      // Push the ENC onto the Stack
      pushEnc();
     
      try
      {
        
         /*
          * Obtain the target method (advised)
          */
         Method unadvisedMethod = method.toMethod(this.getClassloader());
         long hash = MethodHashing.calculateHash(unadvisedMethod);
         MethodInfo info = getAdvisor().getMethodInfo(hash);
         if (info == null)
         {
            throw new RuntimeException("Method invocation via Proxy could not be found handled for EJB "
                  + this.getEjbName() + " : " + method.toString()
                  + ", probable error in virtual method registration w/ Advisor for the Container");
         }

         // Obtain Invocation Handler
         //TODO Ugly, use polymorphism and get Session ID for SFSB only
         assert Proxy.isProxyClass(proxy.getClass());
         SessionProxyInvocationHandler handler = (SessionProxyInvocationHandler)Proxy.getInvocationHandler(proxy);
         Object sessionId = null;
         if (handler instanceof StatefulProxyInvocationHandlerBase)
         {
            sessionId = ((StatefulProxyInvocationHandlerBase) handler).getSessionId();
         }
        
         /*
          * Invoke directly if this is an EJB2.x Method
          */

         if (unadvisedMethod != null && isHomeMethod(method))
         {
            return invokeHomeMethod(method, args);
         }
         else if (unadvisedMethod != null && this.isEjbObjectMethod(method))
         {
            return invokeEJBObjectMethod(sessionId, info, args);
         }

         // FIXME: Ahem, stateful container invocation works on all.... (violating contract though)
         //TODO Use Polymorphism to have sessions only in StatefulContainer
        
//         Interceptor[] interceptors, long methodHash, Method advisedMethod,
//         Method unadvisedMethod, SerializableMethod invokedMethod, Advisor advisor
        
//         StatefulSessionContainerMethodInvocation nextInvocation = new StatefulSessionContainerMethodInvocation(info
//               .getInterceptors(), hash, info.getAdvisedMethod(), info.getUnadvisedMethod(), method, getAdvisor());
        
         /*
          * Build an invocation
          */
        
         StatefulContainerInvocation nextInvocation = new StatefulContainerInvocation(info,sessionId);
         nextInvocation.getMetaData().addMetaData(SessionSpecRemotingMetadata.TAG_SESSION_INVOCATION,
               SessionSpecRemotingMetadata.KEY_INVOKED_METHOD, method);
         nextInvocation.setArguments(args);
        
        
         //nextInvocation.setAdvisor(getAdvisor());
         //nextInvocation.setSessionId(sessionId);
//         EJBContainerInvocation nextInvocation = new StatefulContainerInvocation(info, sessionId);
//         nextInvocation.setAdvisor(getAdvisor());
//         nextInvocation.setArguments(args);

         // allow a container to supplement information into an invocation
         //nextInvocation = populateInvocation(nextInvocation);

         //TODO Support Async Invocation
         //         ProxyUtils.addLocalAsynchronousInfo(nextInvocation, provider);
       
        
         try
         {
            /*
             * Invoke
             */
           
            invokedMethod.push(method);
            return nextInvocation.invokeNext();
         }
         finally
         {
            invokedMethod.pop();
         }


      }
      finally
      {
         Thread.currentThread().setContextClassLoader(oldLoader);
         popEnc();
      }
   }

   public Class<?> getInvokedBusinessInterface()
   {
      //TODO Should be getting from current invocation
      SerializableMethod invokedMethod = SessionSpecContainer.invokedMethod.get();
      assert invokedMethod!=null : "Invoked Method has not been set";
      String interfaceName = invokedMethod.getActualClassName();
      assert interfaceName !=null && interfaceName.trim().length()>0 : "Target Business Interface is not available on invoked method";
      Class<?> invokedInterface = null;
     
      try
      {
         invokedInterface = Class.forName(interfaceName, false, this.getClassloader());
      }
      catch (ClassNotFoundException e)
      {
         throw new RuntimeException("Invoked Business Interface on Proxy was set to " + interfaceName
               + ", but this could not be loaded by the " + ClassLoader.class.getSimpleName() + " for " + this);
      }
//      if (method == null) throw new IllegalStateException("getInvokedBusinessInterface() being invoked outside of a business invocation");
//      if (method.getName() == null || method.getName().equals("")) throw new IllegalStateException("getInvokedBusinessInterface() being invoked outside of a business invocation");
     
//      String invokedBusinessInterfaceClassName = method.getActualClassName();
//      Class<?> invokedBusinessInterface = null;
//      try
//      {
//         invokedBusinessInterface = this.getClassloader().loadClass(invokedBusinessInterfaceClassName);
//      }
//      catch (ClassNotFoundException e)
//      {
//         throw new RuntimeException("Invoked Business Interface on Proxy was set to "
//               + invokedBusinessInterfaceClassName + ", but this could not be loaded by the "
//               + ClassLoader.class.getSimpleName() + " for " + this);
//      }
     
      return invokedInterface;
   }
  
   /**
    * Provides implementation for this bean's EJB 2.1 Home.create() method
    *
    * @param method
    * @param args
    * @return
    * @throws Exception
    */
   protected abstract Object invokeHomeCreate(SerializableMethod method, Object args[]) throws Exception;

   /**
    * TODO: work in progress (refactor both invokeHomeMethod's, localHomeInvoke)
    */
   //TODO
   private Object invokeHomeMethod(SerializableMethod method, Object args[]) throws Exception
   {
      if (method.getName().equals(Ejb2xMethodNames.METHOD_NAME_HOME_CREATE))
      {
         return this.invokeHomeCreate(method, args);
      }
      else if (method.getName().equals(Ejb2xMethodNames.METHOD_NAME_HOME_REMOVE))
      {
         if (args[0] instanceof Handle)
            removeHandle((Handle) args[0]);
         else
            destroySession(args[0]);

         return null;
      }
      else
      {
         throw new IllegalArgumentException("illegal home method " + method);
      }
   }

   /**
    * @deprecated Use isHomeMethod(SerializableMethod method) in SessionSpecContainer
    */
   @Deprecated
   protected boolean isHomeMethod(Method method)
   {
      if (javax.ejb.EJBHome.class.isAssignableFrom(method.getDeclaringClass()))
         return true;
      if (javax.ejb.EJBLocalHome.class.isAssignableFrom(method.getDeclaringClass()))
         return true;
      return false;
   }

   /**
    * Determines whether the specified method is an EJB2.x Home Method
    *
    * @param method
    * @return
    */
   protected boolean isHomeMethod(SerializableMethod method)
   {
      // Get the Method
      Method invokingMethod = method.toMethod(this.getClassloader());

      // Use legacy
      return this.isHomeMethod(invokingMethod);
   }

   /**
    * @param method
    * @return
    * @deprecated Use isEjbObjectMethod(SerializableMethod method)
    */
   @Deprecated
   protected boolean isEJBObjectMethod(Method method)
   {
      /*
       * Initialize
       */
     
      // Get the declaring class
      Class<?> declaringClass = method.getDeclaringClass();
     
      /*
       * Test if declared by EJBObject/EJBLocalObject
       */
     
      if (declaringClass.getName().equals(EJBObject.class.getName()))
         return true;

      if (declaringClass.getName().equals(EJBLocalObject.class.getName()))
         return true;

      return false;
   }

   /**
    * Determines whether the specified method is an EJB2.x Local
    * or Remote Method
    *
    * @param method
    * @return
    */
   protected boolean isEjbObjectMethod(SerializableMethod method)
   {
     
      /*
       * Initialize
       */
     
      // Get the declaring class
      Class<?> declaringClass = null;
      String declaringClassName = method.getDeclaringClassName();
      try
      {
         declaringClass = Class.forName(declaringClassName, false, this.getClassloader());
      }
      catch (ClassNotFoundException e)
      {
         throw new RuntimeException("Invoked Method specifies a declaring class that could not be loaded by the "
               + ClassLoader.class.getSimpleName() + " for EJB " + this.getEjbName());
      }
     
      /*
       * Test if declared by EJBObject/EJBLocalObject
       */
     
      if (declaringClass.getName().equals(EJBObject.class.getName()))
         return true;

      if (declaringClass.getName().equals(EJBLocalObject.class.getName()))
         return true;

      // If we've reached here, not EJBObject/EJBLocalObject
      return false;
   }

   /**
    *
    * @param method
    * @return
    * @deprecated Use isHandleMethod(SerializableMethod method)
    */
   @Deprecated
   protected boolean isHandleMethod(Method method)
   {
      if (method.getDeclaringClass().getName().equals(Handle.class.getName()))
         return true;

      return false;
   }

   /**
    * Determines if the specified Method is a Handle Method
    * @param method
    * @return
    */
   protected boolean isHandleMethod(SerializableMethod method)
   {
      // Get the Method
      Method invokingMethod = method.toMethod(this.getClassloader());

      // Use legacy
      return this.isHandleMethod(invokingMethod);
   }
  
   /**
    * Registers this Container with Remoting / AOP Dispatcher
    */
   @Override
   protected void registerWithAopDispatcher()
   {
      String registrationName = this.getObjectName().getCanonicalName();
      ClassProxy classProxy = new InvokableContextClassProxyHack(this);
     
      // So that Remoting layer can reference this container easily.
      Dispatcher.singleton.registerTarget(registrationName, classProxy);
     
      // Log
      log.debug("Registered " + this + " with " + Dispatcher.class.getName() + " via "
            + InvokableContextClassProxyHack.class.getSimpleName() + " at key " + registrationName);
   }

   // ------------------------------------------------------------------------------||
   // Lifecycle Methods ------------------------------------------------------------||
   // ------------------------------------------------------------------------------||

   public static ClassLoader TMP_CL = null;
  
   /**
    * Lifecycle Start
    */
   @Override
   protected void lockedStart() throws Exception
   {
      log.info("Starting " + this);

      super.lockedStart();

      //TODO
      /*
       * Temporary Hack Alert
       *
       * Populate JBoss-specific metadata until this is done by
       * AnnotationMetaDataDeployer and MergedJBossMetaDataDeployer
       *
       * http://jira.jboss.com/jira/browse/JBMETA-45
       * http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4157770
       */
      log.warn("Populating JBoss-specific annotation metadata manually until done by deployers: " + this);

      // Obtain annotations
      RemoteBindings remoteBindings = this.getAnnotation(RemoteBindings.class);
      RemoteBinding remoteBinding = this.getAnnotation(RemoteBinding.class);
      RemoteHomeBinding remoteHomeBinding = this.getAnnotation(RemoteHomeBinding.class);
      LocalHomeBinding localHomeBinding = this.getAnnotation(LocalHomeBinding.class);
      //      LocalBinding localBinding = this.getAnnotation(LocalBinding.class); // < No LocalBindingMetaData?

      // Create a Set to hold RemoteBindings
      Set<RemoteBinding> remoteBindingsSet = new HashSet<RemoteBinding>();

      // Populate Set with Remote Bindings
      if (remoteBindings != null)
      {
         for (RemoteBinding binding : remoteBindings.value())
         {
            remoteBindingsSet.add(binding);
         }
      }
      if (remoteBinding != null)
      {
         remoteBindingsSet.add(remoteBinding);
      }

      // Ensure remote bindings metadata is not null
      List<RemoteBindingMetaData> rbmd = this.getMetaData().getRemoteBindings();
      if (rbmd == null || rbmd.size() == 0)
      {
         rbmd = new ArrayList<RemoteBindingMetaData>();
         this.getMetaData().setRemoteBindings(rbmd);
      }

      // For each remote binding, populate metadata
      for (RemoteBinding binding : remoteBindingsSet)
      {
         RemoteBindingMetaData md = new RemoteBindingMetaData();
         md.setClientBindUrl(binding.clientBindUrl());
         md.setInterceptorStack(binding.interceptorStack());
         md.setJndiName(binding.jndiBinding());
         md.setProxyFactory(binding.factory());
         //TODO binding.invokerName?
         rbmd.add(md);
      }

      // Populate metadata for @RemoteHomeBinding
      if (remoteHomeBinding != null)
      {
         this.getMetaData().setHomeJndiName(remoteHomeBinding.jndiBinding());
      }

      // Populate metadata for @LocalHomeBinding
      if (localHomeBinding != null)
      {
         this.getMetaData().setLocalHomeJndiName(localHomeBinding.jndiBinding());
      }

      /*
       * End Temporary Hack
       */

      // Obtain registrar
      JndiSessionRegistrarBase registrar = this.getJndiRegistrar();

      // Bind all appropriate references/factories to Global JNDI for Client access, if a JNDI Registrar is present
      if (registrar != null)
      {
         String guid = Ejb3Registry.guid(this);
         registrar.bindEjb(this.getInitialContext(), this.getMetaData(), this.getClassloader(), this.getObjectName()
               .getCanonicalName(), guid, this.getAdvisor());
      }
      else
      {
         log.warn("No " + JndiSessionRegistrarBase.class.getSimpleName()
               + " was found; byassing binding of Proxies to " + this.getName() + " in Global JNDI.");
      }
     
      //TODO Remove
      TMP_CL = this.getClassloader();
   }

   /**
    * Lifecycle Stop
    */
   @Override
   protected void lockedStop() throws Exception
   {
      log.info("Stopping " + this);

      super.lockedStop();

      // Deregister with Remoting
      Dispatcher.singleton.unregisterTarget(this.getName());

      // Unbind applicable JNDI Entries
      JndiSessionRegistrarBase jndiRegistrar = this.getJndiRegistrar();
      if (jndiRegistrar != null)
      {
         jndiRegistrar.unbindEjb(this.getInitialContext(), this.getMetaData());
      }

   }

   // --------------------------------------------------------------------------------||
   // Contracts ----------------------------------------------------------------------||
   // --------------------------------------------------------------------------------||


   /**
    * Returns the name under which the JNDI Registrar for this container is bound
    *
    * @return
    */
   protected abstract String getJndiRegistrarBindName();

   // --------------------------------------------------------------------------------||
   // Accessors / Mutators -----------------------------------------------------------||
   // --------------------------------------------------------------------------------||

   /**
    * Obtains the JndiSessionRegistrarBase from MC, null if not found
    *
    * @return
    */
   protected JndiSessionRegistrarBase getJndiRegistrar()
   {
      // If defined already, use it
      if (this.jndiRegistrar != null)
      {
         return this.jndiRegistrar;
      }

      // Initialize
      String jndiRegistrarBindName = this.getJndiRegistrarBindName();

      // Obtain Registrar
      Ejb3Registrar registrar = Ejb3RegistrarLocator.locateRegistrar();

      // Lookup
      Object obj = null;
      try
      {
         obj = registrar.lookup(jndiRegistrarBindName);
         this.setJndiRegistrar(jndiRegistrar);
      }
      // If not installed, warn and return null
      catch (NotBoundException e)
      {
         log.warn("No " + JndiSessionRegistrarBase.class.getName()
               + " was found installed in the ObjectStore (Registry) at " + jndiRegistrarBindName);
         return null;

      }

      // Cast
      JndiSessionRegistrarBase jndiRegistrar = (JndiSessionRegistrarBase) obj;

      // Return
      return jndiRegistrar;
   }

   public void setJndiRegistrar(JndiSessionRegistrarBase jndiRegistrar)
   {
      this.jndiRegistrar = jndiRegistrar;
   }
}
TOP

Related Classes of org.jboss.ejb3.session.SessionSpecContainer

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.