Package org.jboss.ejb3.proxy.factory.session

Source Code of org.jboss.ejb3.proxy.factory.session.SessionProxyFactoryBase

/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, 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.proxy.factory.session;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.ejb.EJBHome;
import javax.ejb.EJBLocalHome;

import org.jboss.aop.Advisor;
import org.jboss.ejb3.common.lang.ClassHelper;
import org.jboss.ejb3.common.string.StringUtils;
import org.jboss.ejb3.proxy.factory.ProxyFactoryBase;
import org.jboss.ejb3.proxy.handler.session.SessionProxyInvocationHandler;
import org.jboss.ejb3.proxy.intf.SessionProxy;
import org.jboss.logging.Logger;
import org.jboss.metadata.ejb.jboss.JBossSessionBeanMetaData;

/**
* SessionProxyFactoryBase
*
* Base upon which Session Proxy Factory implementations
* may build
*
* @author <a href="mailto:andrew.rubinger@jboss.org">ALR</a>
* @version $Revision: $
*/
public abstract class SessionProxyFactoryBase extends ProxyFactoryBase implements SessionProxyFactory
{

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

   private static final Logger log = Logger.getLogger(SessionProxyFactoryBase.class);

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

   private JBossSessionBeanMetaData metadata;

   /**
    * Constructor for the default Proxy Constructor (All
    * business interfaces and, if bound together, the EJB2.x Home)
    */
   private Constructor<?> constructorProxyDefault;

   /**
    * Map of Proxy Constructors, one per business interface, with key
    * as the fully-qualified class name of the interface, and value
    * of the constructor to use
    */
   private Map<String, Constructor<?>> constructorsProxySpecificBusinessInterface;

   /**
    * Constructor for the EJB2.x Home Proxy
    */
   private Constructor<?> constructorProxyHome;

   /**
    * Constructor for the EJB2.x View Proxy
    */
   private Constructor<?> constructorProxyEjb2x;

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

   /**
    * Constructor
    *
    * @param name The unique name for this ProxyFactory
    * @param containerName The name of the InvokableContext (container)
    *   upon which Proxies will invoke
    * @param containerGuid The globally-unique name of the container
    * @param metadata The metadata representing this Session Bean
    * @param classloader The ClassLoader associated with the Container's Bean Class
    *       for which this ProxyFactory is to generate Proxies
    * @param advisor The Advisor for proxies created by this factory
    */
   public SessionProxyFactoryBase(final String name, final String containerName, final String containerGuid,
         final JBossSessionBeanMetaData metadata, final ClassLoader classloader, final Advisor advisor)
   {
      // Call Super
      super(name, containerName, containerGuid, classloader, advisor);

      // Set Metadata
      this.setMetadata(metadata);

      // Instanciate backing Map for interface-specific business proxies
      this.setConstructorsProxySpecificBusinessInterface(new HashMap<String, Constructor<?>>());
   }

   // --------------------------------------------------------------------------------||
   // Functional Methods -------------------------------------------------------------||
   // --------------------------------------------------------------------------------||

   /**
    * Create an EJB2.x Home Proxy
    *
    * @return
    */
   public Object createProxyHome()
   {
      // Create a new InvocationHandler
      SessionProxyInvocationHandler handler = this.createHomeInvocationHandler();

      try
      {
         // Create a new Proxy instance, and return
         return this.getConstructorProxyHome().newInstance(handler);
      }
      catch (Throwable t)
      {
         // Throw a descriptive error message along with the originating Throwable
         throw new RuntimeException("Could not create Home Proxy for " + this.getMetadata().getEjbName(), t);
      }
   }

   /**
    * Create an EJB3 Business proxy with no
    * specific target business interface.  The
    * returned proxy will implement all appropriate
    * business interfaces.  Additionally, if
    * the Home interface is bound alongside
    * the Default (same JNDI Name), this
    * Proxy will implement the Home interface as well.
    *
    * @return
    */
   public Object createProxyDefault()
   {
      // Obtain Constructor to Default Proxy
      Constructor<?> constructor = this.getConstructorProxyDefault();
      assert constructor != null : "Constructor for Default Proxy was null; perhaps the "
            + SessionProxyFactory.class.getSimpleName() + " was not properly started?";

      // Create a new InvocationHandler
      SessionProxyInvocationHandler handler = this.createBusinessDefaultInvocationHandler();

      try
      {
         // Create a new Proxy instance, and return
         return constructor.newInstance(handler);
      }
      catch (Throwable t)
      {
         // Throw a descriptive error message along with the originating Throwable
         throw new RuntimeException("Could not create the Default Proxy for " + this.getMetadata().getEjbName(), t);
      }
   }

   /**
    * Create an EJB3 Business Proxy specific to the specified
    * target business interface name (expressed as
    * a fully-qualified class name)
    *
    * @param businessInterfaceName
    * @return
    */
   public Object createProxyBusiness(final String businessInterfaceName)
   {
      // Ensure businessInterfaceName is specified
      assert businessInterfaceName != null && businessInterfaceName.trim().length() > 0 : "Required business interface type name was not specified";

      try
      {

         // Obtain the correct business proxy constructor
         Constructor<?> constructor = this.getConstructorsProxySpecificBusinessInterface().get(
               businessInterfaceName.trim());

         // Ensure the constructor was found
         assert constructor != null : "No business proxy constructor for \"" + businessInterfaceName
               + "\" was found; not created at start() properly?  Bad value bound as RefAddr in JNDI?";

         // Create a new InvocationHandler
         SessionProxyInvocationHandler handler = this
               .createBusinessInterfaceSpecificInvocationHandler(businessInterfaceName);

         // Create a new Proxy instance
         Object proxy = constructor.newInstance(handler);
        
         // Return
         return proxy;
      }
      catch (Throwable t)
      {
         // Throw a descriptive error message along with the originating Throwable
         throw new RuntimeException("Could not create the EJB3 Business Proxy implementing \"" + businessInterfaceName
               + "\" for " + this.getMetadata().getEjbName(), t);
      }
   }

   /**
    * Create an EJB2.x Proxy
    *
    * @return
    */
   public Object createProxyEjb2x()
   {
      // Create a new InvocationHandler
      SessionProxyInvocationHandler handler = this.createEjb2xComponentInterfaceInvocationHandler();

      try
      {
         // Create a new Proxy instance, and return
         return this.getConstructorProxyEjb2x().newInstance(handler);
      }
      catch (Throwable t)
      {
         // Throw a descriptive error message along with the originating Throwable
         throw new RuntimeException("Could not create the EJB2.x Proxy for " + this.getMetadata().getEjbName(), t);
      }
   }

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

   /**
    * Lifecycle callback to be invoked
    * before the ProxyFactory is able to service requests
    *
    *  @throws Exception
    */
   @Override
   public void start() throws Exception
   {
      // Call Super
      super.start();

      /*
       * TODO:
       *
       * Yet another method that should be broken apart
       * and analyzed for re-use.
       */

      /*
       * Make Proxies for EJB3 Business Interfaces
       */

      // Obtain Business Interface Types
      Set<String> businessInterfaceTypes = this.getBusinessInterfaceTypes();

      // Initialize
      Set<Class<?>> businessInterfaceClasses = new HashSet<Class<?>>();

      // Determine if business interfaces are defined
      boolean hasBusinessInterfaces = businessInterfaceTypes != null && businessInterfaceTypes.size() > 0;

      // If there are business interfaces
      if (hasBusinessInterfaces)
      {
         // For all business interface types
         for (String businessInterfaceType : businessInterfaceTypes)
         {
            Class<?> businessInterface = null;
            try
            {
               // Load
               businessInterface = this.getClassLoader().loadClass(businessInterfaceType);
            }
            catch (ClassNotFoundException cnfe)
            {
               throw new RuntimeException("Could not find specified Session Bean Business Interface \""
                     + businessInterfaceType + "\" in " + ClassLoader.class.getSimpleName() + " for EJB "
                     + this.getMetadata().getEjbName(), cnfe);
            }

            // Add business interface to classes
            businessInterfaceClasses.add(businessInterface);

            // Make Proxy specific to the business interface
            Set<Class<?>> businessInterfaces = new HashSet<Class<?>>();
            businessInterfaces.add(businessInterface);
            Constructor<?> businessInterfaceConstructor = this.createProxyConstructor(businessInterfaces, this
                  .getClassLoader());
            log.debug("Created Session Bean Business Interface-Specific Proxy Constructor implementing \""
                  + businessInterfaceType + "\"");

            // Set
            this.getConstructorsProxySpecificBusinessInterface().put(businessInterfaceType,
                  businessInterfaceConstructor);

         }
      }

      /*
       * Make Constructor for Home
       */

      // Obtain Home Interface Type
      String homeInterfaceType = this.getHomeType();

      // Determine if Home is defined
      boolean hasHomeInterface = homeInterfaceType != null && !homeInterfaceType.equals("");

      // Ensure Home ad/or Business is defined
      if (!hasHomeInterface && !hasBusinessInterfaces)
      {
         // Throw bean provider descriptive error
         throw new RuntimeException("Cannot deploy EJB " + this.getMetadata().getEjbName()
               + " as it has no EJB3 (Business Interface) or EJB2.x (Home Interface) Views Defined.");
      }

      // Initialize Home Interface Class
      Class<?> homeInterfaceClass = null;

      // If Home is defined
      if (hasHomeInterface)
      {
         try
         {
            // Load the Home class
            homeInterfaceClass = this.getClassLoader().loadClass(homeInterfaceType);
         }
         catch (ClassNotFoundException cnfe)
         {
            throw new RuntimeException("Could not find specified Session Bean Home Interface \"" + homeInterfaceType
                  + "\" in " + ClassLoader.class.getSimpleName() + " for EJB " + this.getMetadata().getEjbName(), cnfe);
         }

         // Make the Home Proxy Constructor
         Set<Class<?>> homeInterfaces = new HashSet<Class<?>>();
         homeInterfaces.add(homeInterfaceClass);
         Constructor<?> homeConstructor = this.createProxyConstructor(homeInterfaces, this.getClassLoader());
         log.debug("Created Session Bean Home Proxy Constructor implementing \"" + homeInterfaceType + "\"");

         // Set the Home Proxy Constructor
         this.setConstructorProxyHome(homeConstructor);
      }

      /*
       * Make Default Proxy
       */

      // Create a Set to hold all relevant interfaces
      Set<Class<?>> defaultProxyInterfaces = new HashSet<Class<?>>();

      // Add all business interfaces
      if (hasBusinessInterfaces)
      {
         defaultProxyInterfaces.addAll(businessInterfaceClasses);
      }

      // If there's a home defined and its bound to the same binding as the default
      if (hasHomeInterface && this.getMetadata().getJndiName().equals(this.getMetadata().getHomeJndiName()))
      {
         defaultProxyInterfaces.add(homeInterfaceClass);
      }

      // Make the Default Business Interfaces Proxy Constructor
      Constructor<?> businessInterfacesConstructor = this.createProxyConstructor(defaultProxyInterfaces, this
            .getClassLoader());
      log.debug("Created Session Bean Default EJB3 Business Proxy Constructor implementing " + defaultProxyInterfaces);

      // Set
      this.setConstructorProxyDefault(businessInterfacesConstructor);

      /*
       * Make Constructor for EJB2.x Views
       */

      // EJB2.x Views may exist only if there is a Home
      if (hasHomeInterface)
      {
         // Initialize Set of EJB2.x Interfaces
         Set<Class<?>> ejb2xInterfaces = new HashSet<Class<?>>();

         // Get return types of create methods (EJB3 Core Specification 3.6.2.1)
         //TODO Should be handled by metadata, see @Deprecated on the method below
         Set<Class<?>> homeReturnTypes = this.getReturnTypesFromCreateMethods(homeInterfaceClass);
         if (homeReturnTypes != null)
         {
            ejb2xInterfaces.addAll(homeReturnTypes);

         }

         // Get explicitly-defined EJB2x interface type
         String ejb2xDeclaredType = StringUtils.adjustWhitespaceStringToNull(this.getEjb2xInterfaceType());

         // If there is an explicitly-defined EJB2.x interface
         if (ejb2xDeclaredType != null)
         {
            Class<?> ejb2xInterface = null;
            try
            {
               // Load
               ejb2xInterface = this.getClassLoader().loadClass(ejb2xDeclaredType);
            }
            catch (ClassNotFoundException cnfe)
            {
               throw new RuntimeException("Could not find specified Session Bean EJB2.x Interface \""
                     + ejb2xDeclaredType + "\" in " + ClassLoader.class.getSimpleName() + " for EJB "
                     + this.getMetadata().getEjbName(), cnfe);
            }

            // Add
            ejb2xInterfaces.add(ejb2xInterface);
         }

         // Make the EJB2.x Proxy Constructor
         Constructor<?> ejb2xConstructor = this.createProxyConstructor(ejb2xInterfaces, this.getClassLoader());
         log.debug("Created Session Bean EJB2x Proxy Constructor implementing " + ejb2xInterfaces);

         // Set the EJB2.x Proxy Constructor
         this.setConstructorProxyEjb2x(ejb2xConstructor);
      }

   }

   /**
    * Lifecycle callback to be invoked by the ProxyFactoryDeployer
    * before the ProxyFactory is taken out of service,
    * possibly GC'd
    *
    * @throws Exception
    */
   @Override
   public void stop() throws Exception
   {
      super.stop();
      //TODO
   }

   /**
    * Returns Proxy interfaces common to all Proxies generated
    * by this ProxyFactory
    *
    * @return
    */
   @Override
   protected Set<Class<?>> getCommonProxyInterfaces()
   {
      // Initialize
      Set<Class<?>> interfaces = super.getCommonProxyInterfaces();

      // Add
      interfaces.add(SessionProxy.class);

      // Return
      return interfaces;
   }

   // --------------------------------------------------------------------------------||
   // Functional Methods -------------------------------------------------------------||
   // --------------------------------------------------------------------------------||

   /**
    * Obtains the return types declared by the "create" methods for the specified home interface.
    *
    * EJB3 Core Specification 3.6.2.1
    * JIRA: EJBTHREE-1127
    * 
    * @param homeInterface
    * @param isStateless Flag to indicate whether this is for a Stateful or Stateless container
    * @return
    * @deprecated http://jira.jboss.com/jira/browse/JBMETA-41
    */
   @Deprecated
   protected Set<Class<?>> getReturnTypesFromCreateMethods(Class<?> homeInterface, boolean isStateless)
   {
      /*
       * TODO
       *
       * Kill the "isStateless" argument, centralize logic as appropriate,
       * and use polymorphsm to properly implement this method.
       *
       * The current structure with the "isStateless" was born out of
       * this function originating as a static utility from EJB3 Core.
       *
       * Note: Perhaps this is a moot point, given the @Deprecated tag
       * and that jboss-metadata should be implementing this.
       */

      // Ensure we've been passed a Home or LocalHome interface (Developers only)
      assert (EJBHome.class.isAssignableFrom(homeInterface) || EJBLocalHome.class.isAssignableFrom(homeInterface));

      // Ensure we've been passed a Home or LocalHome interface (End-User)
      if (!EJBHome.class.isAssignableFrom(homeInterface) && !EJBLocalHome.class.isAssignableFrom(homeInterface))
      {
         throw new RuntimeException("Declared EJB 2.1 Home Interface " + homeInterface.getName() + " does not extend "
               + EJBHome.class.getName() + " or " + EJBLocalHome.class.getName()
               + " as required by EJB 3.0 Core Specification 4.6.8 and 4.6.10");
      }

      // Initialize
      Set<Class<?>> types = new HashSet<Class<?>>();
      List<Method> createMethods = null;

      // If for a Stateless Container
      if (isStateless)
      {
         // Initialize error message
         String specViolationErrorMessage = "EJB 3.0 Specification Violation (4.6.8 Bullet 4, 4.6.10 Bullet 4): \""
               + "A stateless session bean must define exactly one create method with no arguments." + "\"; found in "
               + homeInterface.getName();

         // Get all methods with signature "create"
         createMethods = new ArrayList<Method>();
         try
         {
            createMethods.add(homeInterface.getMethod("create", new Class<?>[]
            {}));
         }
         // EJB 3.0 Specification 4.6.8 Bullet 4 Violation
         // EJBTHREE-1156
         catch (NoSuchMethodException e)
         {
            throw new RuntimeException(specViolationErrorMessage);
         }

         // Ensure only one create method is defined
         // EJB 3.0 Specification 4.6.8 Bullet 4 Violation
         // EJBTHREE-1156
         if (createMethods.size() > 1)
         {
            throw new RuntimeException(specViolationErrorMessage);
         }
      }
      else
      {
         // Obtain all "create<METHOD>" methods
         createMethods = ClassHelper.getAllMethodsByPrefix(homeInterface, "create");
      }
      if (createMethods.size() == 0)
      {
         throw new RuntimeException("EJB 3.0 Core Specification Violation (4.6.8 Bullet 5): EJB2.1 Home Interface "
               + homeInterface + " does not declare a \'create<METHOD>\' method");
      }

      // Add all return types
      for (Method method : createMethods)
      {
         types.add(method.getReturnType());
      }

      // Return
      return types;
   }

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

   /**
    * Returns the a Set of String representations of the Business Interface Types
    *
    *  @return
    */
   protected abstract Set<String> getBusinessInterfaceTypes();

   /**
    * Returns the String representation of the Home Interface Type
    * @return
    */
   protected abstract String getHomeType();

   /**
    * Returns the String representation of the EJB2.x Interface Types
    *
    *  @return
    */
   protected abstract String getEjb2xInterfaceType();

   /**
    * Obtains the return types declared by the "create" methods for the specified home interface.
    * 
    * @param homeInterface
    * @return
    */
   protected abstract Set<Class<?>> getReturnTypesFromCreateMethods(Class<?> homeInterface);

   /**
    * Returns the Constructor of the SessionProxyInvocationHandler to be used in
    * instanciating new handlers to specify in Proxy Creation
    *
    * Used for creating a Handler for a Business Interface-specific proxy
    *
    * @return
    */
   protected abstract SessionProxyInvocationHandler createBusinessInterfaceSpecificInvocationHandler(
         String businessInterfaceName);

   /**
    * Returns the Constructor of the SessionProxyInvocationHandler to be used in
    * instanciating new handlers to specify in Proxy Creation
    *
    * Used for creating a Handler for a Business Default proxy
    *
    * @return
    */
   protected abstract SessionProxyInvocationHandler createBusinessDefaultInvocationHandler();

   /**
    * Returns the Constructor of the SessionProxyInvocationHandler to be used in
    * instanciating new handlers to specify in Proxy Creation
    *
    * Used for creating a Handler for an EJB2.x Component Interface proxy
    *
    * @return
    */
   protected abstract SessionProxyInvocationHandler createEjb2xComponentInterfaceInvocationHandler();

   /**
    * Returns the Constructor of the SessionProxyInvocationHandler to be used in
    * instanciating new handlers to specify in Proxy Creation
    *
    * Used for creating a Handler for am EJB2.x Home proxy
    *
    * @return
    */
   protected abstract SessionProxyInvocationHandler createHomeInvocationHandler();

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

   public JBossSessionBeanMetaData getMetadata()
   {
      return metadata;
   }

   protected void setMetadata(final JBossSessionBeanMetaData metadata)
   {
      this.metadata = metadata;
   }

   protected Constructor<?> getConstructorProxyDefault()
   {
      return constructorProxyDefault;
   }

   protected void setConstructorProxyDefault(Constructor<?> constructorProxyDefault)
   {
      this.constructorProxyDefault = constructorProxyDefault;
   }

   protected Map<String, Constructor<?>> getConstructorsProxySpecificBusinessInterface()
   {
      return constructorsProxySpecificBusinessInterface;
   }

   protected void setConstructorsProxySpecificBusinessInterface(
         Map<String, Constructor<?>> constructorsProxySpecificBusinessInterface)
   {
      this.constructorsProxySpecificBusinessInterface = constructorsProxySpecificBusinessInterface;
   }

   protected Constructor<?> getConstructorProxyHome()
   {
      return constructorProxyHome;
   }

   protected void setConstructorProxyHome(Constructor<?> constructorProxyHome)
   {
      this.constructorProxyHome = constructorProxyHome;
   }

   protected Constructor<?> getConstructorProxyEjb2x()
   {
      return constructorProxyEjb2x;
   }

   protected void setConstructorProxyEjb2x(Constructor<?> constructorProxyEjb2x)
   {
      this.constructorProxyEjb2x = constructorProxyEjb2x;
   }

}
TOP

Related Classes of org.jboss.ejb3.proxy.factory.session.SessionProxyFactoryBase

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.