Package org.jboss.ejb3.proxy.factory

Source Code of org.jboss.ejb3.proxy.factory.ProxyFactoryHelper

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

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.ejb.EJBHome;
import javax.ejb.EJBLocalHome;
import javax.ejb.EJBLocalObject;
import javax.ejb.EJBObject;
import javax.ejb.Local;
import javax.ejb.LocalHome;
import javax.ejb.Remote;
import javax.ejb.RemoteHome;
import javax.jws.WebService;
import javax.management.ObjectInstance;
import javax.management.ObjectName;

import org.jboss.ejb3.Container;
import org.jboss.ejb3.DeploymentScope;
import org.jboss.ejb3.EJBContainer;
import org.jboss.ejb3.KernelAbstraction;
import org.jboss.ejb3.KernelAbstractionFactory;
import org.jboss.ejb3.annotation.JndiBindingPolicy;
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.annotation.impl.LocalImpl;
import org.jboss.ejb3.annotation.impl.RemoteImpl;
import org.jboss.ejb3.common.lang.ClassHelper;
import org.jboss.ejb3.jndipolicy.impl.PackagingBasedJndiBindingPolicy;
import org.jboss.ejb3.service.ServiceContainer;
import org.jboss.ejb3.session.SessionContainer;
import org.jboss.ejb3.stateful.StatefulContainer;
import org.jboss.ejb3.stateless.StatelessContainer;
import org.jboss.logging.Logger;
import org.jboss.metadata.ejb.jboss.jndipolicy.spi.DefaultJndiBindingPolicy;
import org.jboss.metadata.ejb.jboss.jndipolicy.spi.EjbDeploymentSummary;

/**
* Comment
*
* @author <a href="mailto:bill@jboss.org">Bill Burke</a>
* @version $Revision: 75099 $
*/
public class ProxyFactoryHelper
{
   private static final Logger log = Logger.getLogger(ProxyFactoryHelper.class);

   private static String getEndpointInterface(Container container)
   {
      WebService ws = (javax.jws.WebService) ((EJBContainer) container).resolveAnnotation(javax.jws.WebService.class);
      if (ws != null)
      {
         return ws.endpointInterface();
      }
      return null;
   }

   /**
    *
    * @param container
    * @return       the local interfaces of the container or an empty array
    */
   public static Class<?>[] getLocalAndBusinessLocalInterfaces(Container container)
   {
      // Initialize
      Set<Class<?>> localAndBusinessLocalInterfaces = new HashSet<Class<?>>();

      // Obtain Bean Class
      Class<?> beanClass = container.getBeanClass();

      // Obtain @Local
      Local localAnnotation = ((EJBContainer) container).getAnnotation(Local.class);

      // Obtain @LocalHome
      LocalHome localHomeAnnotation = ((EJBContainer) container).getAnnotation(LocalHome.class);

      // Obtain @Remote
      Remote remoteAnnotation = ((EJBContainer) container).getAnnotation(Remote.class);

      // Obtain Remote and Business Remote interfaces
      Class<?>[] remoteAndBusinessRemoteInterfaces = ProxyFactoryHelper.getRemoteAndBusinessRemoteInterfaces(container);

      // Obtain all business interfaces from the bean class
      Set<Class<?>> businessInterfacesImplementedByBeanClass = ProxyFactoryHelper.getBusinessInterfaces(beanClass);

      // Obtain all business interfaces directly implemented by the bean class (not including supers)
      Set<Class<?>> businessInterfacesDirectlyImplementedByBeanClass = ProxyFactoryHelper.getBusinessInterfaces(
            beanClass, false);

      // Determine whether Stateful or Stateless
      boolean isStateless = (container instanceof StatelessContainer) ? true : false;

      // EJBTHREE-1127
      // Determine local interface from return value of "create" in Local Home
      if (localHomeAnnotation != null)
      {
         localAndBusinessLocalInterfaces.addAll(ProxyFactoryHelper.getReturnTypesFromCreateMethods(localHomeAnnotation
               .value(), isStateless));
      }

      // For each of the business interfaces implemented by the bean class
      for (Class<?> clazz : businessInterfacesImplementedByBeanClass)
      {
         // If @Local is on the interface
         if (clazz.isAnnotationPresent(Local.class))
         {
            // Add to the list of locals
            localAndBusinessLocalInterfaces.add(clazz);
         }
      }

      // EJBTHREE-1062
      // EJB 3 Core Specification 4.6.6
      // If bean class implements a single interface, that interface is assumed to be the
      // business interface of the bean. This business interface will be a local interface unless the
      // interface is designated as a remote business interface by use of the Remote
      // annotation on the bean class or interface or by means of the deployment descriptor.
      if (businessInterfacesDirectlyImplementedByBeanClass.size() == 1 && localAndBusinessLocalInterfaces.size() == 0)
      {
         // Obtain the implemented interface
         Class<?> singleInterface = businessInterfacesDirectlyImplementedByBeanClass.iterator().next();

         // If not explicitly marked as @Remote, and is a valid business interface
         if (remoteAnnotation == null && singleInterface.getAnnotation(Remote.class) == null)
         {
            // Return the implemented interface, adding to the container 
            Class<?>[] returnValue = new Class[]
            {singleInterface};
            Local li = new LocalImpl(returnValue);
            ((EJBContainer) container).getAnnotations().addClassAnnotation(Local.class, li);
            return returnValue;
         }
      }

      // @Local was defined
      if (localAnnotation != null)
      {
         // If @Local has no value or empty value
         if (localAnnotation.value() == null || localAnnotation.value().length == 0)
         {
            // If @Local is defined with no value and there are no business interfaces
            if (businessInterfacesImplementedByBeanClass.size() == 0)
            {
               throw new RuntimeException("Use of empty @Local on bean " + container.getEjbName()
                     + " and there are no valid business interfaces");
            }
            // If more than one business interface is directly implemented by the bean class
            else if (businessInterfacesImplementedByBeanClass.size() > 1)
            {
               throw new RuntimeException("Use of empty @Local on bean " + container.getEjbName()
                     + " with more than one default interface " + businessInterfacesImplementedByBeanClass);
            }
            // JIRA EJBTHREE-1062
            // EJB 3 4.6.6
            // If the bean class implements only one business interface, that
            //interface is exposed as local business if not denoted as @Remote
            else
            {
               // If not explicitly marked as @Remote
               if (remoteAnnotation == null)
               {
                  // Return the implemented interface and add to container
                  Class<?>[] returnValue = businessInterfacesImplementedByBeanClass.toArray(new Class<?>[]
                  {});
                  Local li = new LocalImpl(returnValue);
                  ((EJBContainer) container).getAnnotations().addClassAnnotation(Local.class, li);
                  return returnValue;
               }
            }
         }
         // @Local has value
         else
         {
            // For each of the interfaces in @Local.value
            for (Class<?> clazz : localAnnotation.value())
            {
               // Add to the list of locals
               localAndBusinessLocalInterfaces.add(clazz);
            }

            // For each of the business interfaces implemented by the bean class
            for (Class<?> clazz : businessInterfacesImplementedByBeanClass)
            {
               // If @Local is on the interface
               if (clazz.isAnnotationPresent(Local.class))
               {
                  // Add to the list of locals
                  localAndBusinessLocalInterfaces.add(clazz);
               }
            }
         }
      }

      // If local interfaces have been defined/discovered
      if (localAndBusinessLocalInterfaces.size() > 0)
      {
         // Check to ensure @Local and @Remote are not defined on the same interface
         // EJBTHREE-751
         for (Class<?> remoteInterface : remoteAndBusinessRemoteInterfaces)
         {
            for (Class<?> localInterface : localAndBusinessLocalInterfaces)
            {
               if (localInterface.equals(remoteInterface))
               {
                  throw new RuntimeException("@Remote and @Local may not both be specified on the same interface \""
                        + remoteInterface.toString() + "\" per EJB3 Spec 4.6.6, Bullet 5.4");
               }
            }
         }

         // Return local interfaces, first adding to the container
         Class<?>[] rtn = localAndBusinessLocalInterfaces.toArray(new Class<?>[]
         {});
         localAnnotation = new LocalImpl(rtn);
         ((EJBContainer) container).getAnnotations().addClassAnnotation(Local.class, localAnnotation);
         return rtn;
      }
      // If no local interfaces have been defined/discovered
      else
      {
         // Obtain WS Endpoint
         String endpoint = ProxyFactoryHelper.getEndpointInterface(container);

         // If neither WS Endpoint or remotes are defined
         if (remoteAndBusinessRemoteInterfaces.length == 0 && endpoint == null)
            throw new RuntimeException(
                  "Bean Class "
                        + beanClass.getName()
                        + " has no local, webservice, or remote interfaces defined and does not implement at least one business interface: "
                        + container.getEjbName());

      }

      // No local or business local interfaces discovered
      return new Class<?>[]
      {};
   }

   /**
    * Resolve the potential business interfaces on an enterprise bean.
    * Returns all interfaces implemented by this class and its supers which
    * are potentially a business interface.
    *
    * Note: for normal operation call container.getBusinessInterfaces().
    *
    * @param    beanClass   the EJB implementation class
    * @return   a list of potential business interfaces
    * @see      org.jboss.ejb3.EJBContainer#getBusinessInterfaces()
    */
   public static Set<Class<?>> getBusinessInterfaces(Class<?> beanClass)
   {
      // Obtain all business interfaces implemented by this bean class and its superclasses
      return ProxyFactoryHelper.getBusinessInterfaces(beanClass, new HashSet<Class<?>>());
   }

   /**
    * Resolve the potential business interfaces on an enterprise bean.
    * Returns all interfaces implemented by this class and, optionally, its supers which
    * are potentially a business interface.
    *
    * Note: for normal operation call container.getBusinessInterfaces().
    *
    * @param    beanClass   the EJB implementation class
    * @param    includeSupers Whether or not to include superclasses of the specified beanClass in this check
    * @return   a list of potential business interfaces
    * @see      org.jboss.ejb3.EJBContainer#getBusinessInterfaces()
    */
   public static Set<Class<?>> getBusinessInterfaces(Class<?> beanClass, boolean includeSupers)
   {
      // Obtain all business interfaces implemented by this bean class and optionally, its superclass
      return ProxyFactoryHelper.getBusinessInterfaces(beanClass, new HashSet<Class<?>>(), includeSupers);
   }

   private static Set<Class<?>> getBusinessInterfaces(Class<?> beanClass, Set<Class<?>> interfaces)
   {
      return ProxyFactoryHelper.getBusinessInterfaces(beanClass, interfaces, true);
   }

   private static Set<Class<?>> getBusinessInterfaces(Class<?> beanClass, Set<Class<?>> interfaces,
         boolean includeSupers)
   {
      /*
       * 4.6.6:
       * The following interfaces are excluded when determining whether the bean class has
       * more than one interface: java.io.Serializable; java.io.Externalizable;
       * any of the interfaces defined by the javax.ejb package.
       */
      for (Class<?> intf : beanClass.getInterfaces())
      {
         if (intf.equals(java.io.Externalizable.class))
            continue;
         if (intf.equals(java.io.Serializable.class))
            continue;
         if (intf.getName().startsWith("javax.ejb"))
            continue;

         // FIXME Other aop frameworks might add other interfaces, this should really be configurable
         if (intf.getName().startsWith("org.jboss.aop"))
            continue;

         interfaces.add(intf);
      }

      // If there's no superclass, or we shouldn't check the superclass, return
      if (!includeSupers || beanClass.getSuperclass() == null)
      {
         return interfaces;
      }
      else
      {
         // Include any superclasses' interfaces
         return getBusinessInterfaces(beanClass.getSuperclass(), interfaces);
      }
   }

   public static Class<?> getLocalHomeInterface(Container container)
   {
      LocalHome li = ((EJBContainer) container).getAnnotation(javax.ejb.LocalHome.class);
      if (li != null)
         return li.value();
      return null;
   }

   public static Class<?> getRemoteHomeInterface(Container container)
   {
      RemoteHome li = ((EJBContainer) container).getAnnotation(javax.ejb.RemoteHome.class);
      if (li != null)
         return li.value();
      return null;
   }

   public static boolean publishesInterface(Container container, Class<?> businessInterface)
   {
      if (!(container instanceof SessionContainer))
         return false;
      Class<?>[] remotes = getRemoteAndBusinessRemoteInterfaces(container);
      for (Class<?> intf : remotes)
      {
         if (intf.getName().equals(businessInterface.getName()))
            return true;
      }

      Class<?> remoteHome = getRemoteHomeInterface(container);
      if (remoteHome != null)
      {
         if (businessInterface.getName().equals(remoteHome.getName()))
         {
            return true;
         }
      }
      Class<?>[] locals = getLocalAndBusinessLocalInterfaces(container);
      for (Class<?> clazz : locals)
      {
         if (clazz.getName().equals(businessInterface.getName()))
         {
            return true;
         }
      }
      Class<?> localHome = getLocalHomeInterface(container);
      if (localHome != null)
      {
         if (businessInterface.getName().equals(localHome.getName()))
         {
            return true;
         }
      }

      return false;
   }

   /**
    * Obtains the JNDI name for the specified container; may either be explicitly-defined by
    * annotation / XML or will otherwise default to the configured JNDI Binding Policy
    *
    * @param container
    * @param businessInterface
    * @return
    */
   public static String getJndiName(EJBContainer container, Class<?> businessInterface)
   {
      assert container != null : "container is null";
      assert businessInterface != null : "businessInterface is null";

      // Initialize to defaults of remote and not home
      String jndiName = null;
      boolean isHome = false;
      boolean isLocal = false;

      // Determine if remote
      Class<?>[] remotes = ProxyFactoryHelper.getRemoteAndBusinessRemoteInterfaces(container);
      for (Class<?> clazz : remotes)
      {
         if (clazz.getName().equals(businessInterface.getName()))
         {
            // Check for declared @RemoteBindings
            RemoteBindings bindings = ((EJBContainer) container).getAnnotation(RemoteBindings.class);
            if (bindings != null)
            {
               // Encountered, return
               return bindings.value()[0].jndiBinding();
            }
            // Check for declared @RemoteBinding
            RemoteBinding binding = ((EJBContainer) container).getAnnotation(RemoteBinding.class);
            if (binding != null)
            {
               // Encountered, return
               return binding.jndiBinding();
            }
         }
      }

      // Determine if remote home
      Class<?> remoteHome = getRemoteHomeInterface(container);
      if (remoteHome != null)
      {
         if (businessInterface.getName().equals(remoteHome.getName()))
         {
            // Check for declared @RemoteHomeBinding
            RemoteHomeBinding binding = ((EJBContainer) container).getAnnotation(RemoteHomeBinding.class);
            if (binding != null)
            {
               // Encountered, return
               return binding.jndiBinding();
            }

            // Set home for policy
            isHome = true;
         }
      }

      // Determine if local and home
      Class<?> localHome = getLocalHomeInterface(container);
      if (localHome != null)
      {
         if (businessInterface.getName().equals(localHome.getName()))
         {
            // Check for declared @LocalHomeBinding
            LocalHomeBinding binding = ((EJBContainer) container).getAnnotation(LocalHomeBinding.class);
            if (binding != null)
            {
               // Encountered, return
               return binding.jndiBinding();
            }

            // Set local and home for policy
            isHome = true;
            isLocal = true;
         }
      }

      // Determine if local
      Class<?>[] locals = getLocalAndBusinessLocalInterfaces(container);
      for (Class<?> clazz : locals)
      {
         if (clazz.getName().equals(businessInterface.getName()))
         {
            // Check for declared @LocalBinding
            LocalBinding binding = ((EJBContainer) container).getAnnotation(LocalBinding.class);
            if (binding != null)
            {
               // Encountered, return
               return binding.jndiBinding();
            }

            // Set local for policy
            isLocal = true;
         }
      }

      // If JNDI Name has not been explicitly specified, use policy
      if (jndiName == null)
      {
         // Log
         log.debug("JNDI name has not been explicitly set for EJB " + container.getEjbName() + ", interface "
               + businessInterface.getName());

         // Set JNDI name
         EjbDeploymentSummary summary = ProxyFactoryHelper.getDeploymentSummaryFromContainer(container);
         summary.setHome(isHome);
         summary.setLocal(isLocal);
         jndiName = ProxyFactoryHelper.getJndiBindingPolicy(container).getJndiName(summary);
      }

      // Return
      return jndiName;
   }

   /**
    * Returns all local interfaces in the specified container; interfaces
    * marked as "local" via either annotation or XML and extending EJBLocalObject
    *
    * @param container
    * @return
    */
   public static Class<?>[] getLocalInterfaces(Container container)
   {
      return ProxyFactoryHelper.getInterfacesAssignableFromClass(ProxyFactoryHelper
            .getLocalAndBusinessLocalInterfaces(container), EJBLocalObject.class, true);
   }

   /**
    * Returns all remote interfaces in the specified container; interfaces
    * marked as "remote" via either annotation or XML and extending EJBObject
    *
    * @param container
    * @return
    */
   public static Class<?>[] getRemoteInterfaces(Container container)
   {
      return ProxyFactoryHelper.getInterfacesAssignableFromClass(ProxyFactoryHelper
            .getRemoteAndBusinessRemoteInterfaces(container), EJBObject.class, true);
   }

   /**
    * Returns all local business interfaces in the specified container; interfaces
    * marked as "local" via either annotation or XML and not extending EJBLocalObject
    *
    * @param container
    * @return
    */
   public static Class<?>[] getLocalBusinessInterfaces(Container container)
   {
      return ProxyFactoryHelper.getInterfacesAssignableFromClass(ProxyFactoryHelper
            .getLocalAndBusinessLocalInterfaces(container), EJBLocalObject.class, false);
   }

   /**
    * Returns all remote business interfaces in the specified container; interfaces
    * marked as "remote" via either annotation or XML and not extending EJBObject
    *
    * @param container
    * @return
    */
   public static Class<?>[] getRemoteBusinessInterfaces(Container container)
   {
      return ProxyFactoryHelper.getInterfacesAssignableFromClass(ProxyFactoryHelper
            .getRemoteAndBusinessRemoteInterfaces(container), EJBObject.class, false);
   }

   /**
    * Returns an subset of the specified array of interfaces either
    * assignable to or not assignable to the specified class, depending
    * upon the flag "assignable"
    *
    * @param interfaces
    * @param clazz
    * @param assignable
    * @return
    */
   private static Class<?>[] getInterfacesAssignableFromClass(Class<?>[] interfaces, Class<?> clazz, boolean assignable)
   {
      // Initialize
      List<Class<?>> subset = new ArrayList<Class<?>>();

      // For all interfaces 
      for (Class<?> interfaze : interfaces)
      {
         // If we want assignable classes only
         if (assignable && clazz.isAssignableFrom(interfaze))
         {
            subset.add(interfaze);
         }

         // If we want classes not assignable only
         if (!assignable && !clazz.isAssignableFrom(interfaze))
         {
            subset.add(interfaze);
         }
      }

      // Return
      return subset.toArray(new Class<?>[]
      {});
   }

   /**
    * Returns all remote and remote business interfaces in the specified container,
    * designated by @Remote or in ejb-jar.xml as "remote" or "business-remote"
    *
    * @param container
    * @return   the remote interfaces of the container or an empty array
    */
   public static Class<?>[] getRemoteAndBusinessRemoteInterfaces(Container container)
   {
      // Initialize
      Remote remoteAnnotation = ((EJBContainer) container).getAnnotation(Remote.class);
      RemoteHome remoteHomeAnnotation = ((EJBContainer) container).getAnnotation(RemoteHome.class);
      Set<Class<?>> remoteAndRemoteBusinessInterfaces = new HashSet<Class<?>>();
      Class<?> beanClass = container.getBeanClass();
      boolean isStateless = (container instanceof StatelessContainer) ? true : false;

      // Obtain business interfaces
      Class<?>[] businessInterfaces = ProxyFactoryHelper.getBusinessInterfaces(beanClass).toArray(new Class[]
      {});

      // EJBTHREE-1127
      // Determine remote interface from return value of "create" in Remote Home
      if (remoteHomeAnnotation != null)
      {
         remoteAndRemoteBusinessInterfaces.addAll(ProxyFactoryHelper.getReturnTypesFromCreateMethods(
               remoteHomeAnnotation.value(), isStateless));
      }

      // If @Remote is not defined
      if (remoteAnnotation == null)
      {
         // For each of the business interfaces
         for (Class<?> clazz : businessInterfaces)
         {
            // If @Remote is on the business interface
            if (clazz.isAnnotationPresent(Remote.class))
            {
               // Add to the list of remotes
               remoteAndRemoteBusinessInterfaces.add(clazz);
            }
         }
      }
      // @Remote was defined
      else
      {
         // @Remote declares interfaces, add these
         if (remoteAnnotation.value().length > 0)
         {
            for (Class<?> clazz : remoteAnnotation.value())
            {
               remoteAndRemoteBusinessInterfaces.add(clazz);
            }
         }
         // @Remote is empty
         else
         {
            // No business interfaces were defined on the bean
            if (businessInterfaces.length == 0)
            {
               throw new RuntimeException("Use of empty @Remote on bean " + container.getEjbName()
                     + " and there are no valid business interfaces");
            }

            // More than one default interface, cannot be marked as @Remote
            else if (businessInterfaces.length > 1)
            {
               throw new RuntimeException("Use of empty @Remote on bean " + container.getEjbName()
                     + " with more than one default interface " + businessInterfaces);
            }
            // Only one default interface, mark as @Remote and return
            else
            {
               Class<?>[] rtn =
               {(Class<?>) businessInterfaces[0]};
               remoteAnnotation = new RemoteImpl(rtn);
               ((EJBContainer) container).getAnnotations().addClassAnnotation(javax.ejb.Remote.class, remoteAnnotation);
               return rtn;
            }
         }
      }

      // If remotes were found
      if (remoteAndRemoteBusinessInterfaces.size() > 0)
      {
         // Set interfaces and return
         Class<?>[] remotesArray = remoteAndRemoteBusinessInterfaces
               .toArray(new Class[remoteAndRemoteBusinessInterfaces.size()]);
         remoteAnnotation = new RemoteImpl(remotesArray);
         ((EJBContainer) container).getAnnotations().addClassAnnotation(Remote.class, remoteAnnotation);
         return remoteAnnotation.value();
      }
      // No remotes were found
      else
      {
         return new Class<?>[]
         {};
      }
   }

   /**
    * Obtains the return types declared by the "create" methods for the specified home interface.
    * 
    * @param homeInterface
    * @param isStateless Flag to indicate whether this is for a Stateful or Stateless container
    * @return
    */
   private static Set<Class<?>> getReturnTypesFromCreateMethods(Class<?> homeInterface, boolean isStateless)
   {
      // 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;
   }
  
   public static String getClientBindUrl(RemoteBinding binding) throws Exception
   {
      String clientBindUrl = binding.clientBindUrl();
      if (clientBindUrl.trim().length() == 0)
      {
         if (binding.invokerName()!=null && binding.invokerName().trim().length() != 0)
         {
            try
            {
               ObjectName connectionON = new ObjectName(binding.invokerName());
               KernelAbstraction kernelAbstraction = KernelAbstractionFactory.getInstance();
               clientBindUrl = (String)kernelAbstraction.getAttribute(connectionON, "InvokerLocator");
            }
            catch (Exception e)
            {
               log.warn("Unable to find InvokerLocator " + binding.invokerName() + ". Using default. " + e);
               clientBindUrl = RemoteProxyFactory.DEFAULT_CLIENT_BINDING;
            }
         }
         else
         {
            try
            {
               ObjectName connectionON = new ObjectName("jboss.remoting:type=Connector,name=DefaultEjb3Connector,handler=ejb3");
               KernelAbstraction kernelAbstraction = KernelAbstractionFactory.getInstance();
               clientBindUrl = (String)kernelAbstraction.getAttribute(connectionON, "InvokerLocator");
            }
            catch (Exception e)
            {
               log.warn("Unable to find default InvokerLocator. Using default. " + e);
               clientBindUrl = RemoteProxyFactory.DEFAULT_CLIENT_BINDING;
            }
         }
      }
      else if (clientBindUrl.indexOf("0.0.0.0") != -1)
      {
         KernelAbstraction kernelAbstraction = KernelAbstractionFactory.getInstance();
         ObjectName query = new ObjectName("jboss.remoting:type=Connector,handler=ejb3,*");
         Set mbeanSet = kernelAbstraction.getMBeans(query);
        
         URI targetUri = new URI(clientBindUrl);
         Iterator mbeans = mbeanSet.iterator();
         while (mbeans.hasNext())
         {
            ObjectInstance invokerInstance = (ObjectInstance)mbeans.next();
            ObjectName invokerName = invokerInstance.getObjectName();
            String invokerLocator = (String)kernelAbstraction.getAttribute(invokerName, "InvokerLocator");
            URI uri = new URI(invokerLocator);
         
            if (uri.getScheme().equals(targetUri.getScheme()) && uri.getPort() == targetUri.getPort())
            {
               return invokerLocator;
            }
         }
      }
     
      if (clientBindUrl == null)
         clientBindUrl = RemoteProxyFactory.DEFAULT_CLIENT_BINDING;
     
      return clientBindUrl;
   }
  
   /**
    * Create a Proxy Constructor for the specified interfaces, using the specified CL
    *
    * @param interfaces
    * @param cl
    * @return
    * @throws Exception
    */
   public static Constructor<?> createProxyConstructor(Class<?>[] interfaces, ClassLoader cl) throws Exception
   {
      Class<?> proxyClass = java.lang.reflect.Proxy.getProxyClass(cl, interfaces);
      return proxyClass.getConstructor(InvocationHandler.class);
   }

   public static String getHomeJndiName(EJBContainer container)
   {
      // Use explicitly-specified binding, if defined
      RemoteHomeBinding binding = container.getAnnotation(RemoteHomeBinding.class);
      if (binding != null)
         return binding.jndiBinding();

      // Use Default JNDI Binding Policy
      return ProxyFactoryHelper.getJndiBindingPolicy(container).getDefaultRemoteHomeJndiName(
            ProxyFactoryHelper.getDeploymentSummaryFromContainer(container));
   }

   public static String getLocalHomeJndiName(EJBContainer container)
   {
      // Use explicitly-specified binding, if defined
      LocalHomeBinding binding = container.getAnnotation(LocalHomeBinding.class);
      if (binding != null)
         return binding.jndiBinding();

      // Use Default JNDI Binding Policy
      return ProxyFactoryHelper.getJndiBindingPolicy(container).getDefaultLocalHomeJndiName(
            ProxyFactoryHelper.getDeploymentSummaryFromContainer(container));
   }

   public static String getLocalJndiName(EJBContainer container)
   {
      return ProxyFactoryHelper.getLocalJndiName(container, true);
   }

   private static String getLocalJndiName(EJBContainer container, boolean conflictCheck)
   {
      // See if local binding is explicitly-defined
      LocalBinding localBinding = container.getAnnotation(LocalBinding.class);

      // If none specified
      if (localBinding == null)
      {
         // Get JNDI name from policy
         String name = ProxyFactoryHelper.getJndiBindingPolicy(container).getDefaultLocalJndiName(
               ProxyFactoryHelper.getDeploymentSummaryFromContainer(container));

         // If we should check for naming conflict
         if (conflictCheck){
            // Check
            ProxyFactoryHelper.checkForJndiNamingConflict(container);
         }

         // Return
         return name;
      }
      // Local Binding was explicitly-specified, use it
      else
      {
         return localBinding.jndiBinding();
      }
   }

   public static String getRemoteBusinessJndiName(EJBContainer container)
   {
      return ProxyFactoryHelper.getRemoteBusinessJndiName(container, true);
   }

   public static String getRemoteBusinessJndiName(EJBContainer container, boolean check)
   {
      RemoteBinding binding = container.getAnnotation(RemoteBinding.class);

      return ProxyFactoryHelper.getRemoteBusinessJndiName(container, binding);
   }

   private static void checkForJndiNamingConflict(EJBContainer container)
   {
      if (container.getAnnotation(Local.class) != null)
      {
         EjbDeploymentSummary summary = ProxyFactoryHelper.getDeploymentSummaryFromContainer(container);
         String localJndiName = ProxyFactoryHelper.getJndiBindingPolicy(container).getDefaultLocalJndiName(summary);
         String remoteJndiName = ProxyFactoryHelper.getJndiBindingPolicy(container).getDefaultRemoteJndiName(summary);
         String ejbName = container.getEjbName();
         if ((localJndiName.equals(remoteJndiName)))
         {
            throw new javax.ejb.EJBException("Conflict between default jndi name " + remoteJndiName
                  + " for both remote and local for ejb-name:" + ejbName + ", bean class=" + container.getBeanClass());
         }

      }
   }

   private static String getRemoteBusinessJndiName(EJBContainer container, RemoteBinding binding)
   {
      return ProxyFactoryHelper.getRemoteBusinessJndiName(container, binding, true);
   }

   public static String getRemoteBusinessJndiName(EJBContainer container, RemoteBinding binding, boolean conflictCheck)
   {
      // Initialize
      String jndiName = null;

      // If binding is not defined
      if (binding == null || binding.jndiBinding() == null || binding.jndiBinding().trim().equals(""))
      {
         // Use the default
         jndiName = getDefaultRemoteBusinessJndiName(container);

         // If we should check for a naming conflict
         if (conflictCheck)
         {
            // Check
            ProxyFactoryHelper.checkForJndiNamingConflict(container);
         }

      }
      // Binding is explicitly-defined
      else
      {
         // use it
         jndiName = binding.jndiBinding();
      }

      // Return
      return jndiName;
   }

   public static String getDefaultRemoteBusinessJndiName(EJBContainer container)
   {
      // Obtain JNDI Binding Policy
      DefaultJndiBindingPolicy policy = ProxyFactoryHelper.getJndiBindingPolicy(container);

      // Obtain Deployment Summary
      EjbDeploymentSummary summary = ProxyFactoryHelper.getDeploymentSummaryFromContainer(container);

      // Return the policy's default remote name for this summary
      return policy.getDefaultRemoteJndiName(summary);
   }

   /**
    * Obtains the JNDI Binding Policy for the specified container
    *
    * @param container
    * @author ALR
    * @return
    */
   private static DefaultJndiBindingPolicy getJndiBindingPolicy(EJBContainer container)
   {
      // Attempt to obtain the binding policy from annotation repo
      JndiBindingPolicy bindingPolicy = container.getAnnotation(JndiBindingPolicy.class);

      // Initialize
      Class<? extends DefaultJndiBindingPolicy> policy = null;
     
      // If policy is defined
      if (bindingPolicy != null){
         // Use it
         policy = bindingPolicy.policy();
      }
      // No policy defined
      else
      {
         // Use default policy
         Class<? extends DefaultJndiBindingPolicy> policyClass = PackagingBasedJndiBindingPolicy.class;
         // Log warning
         log.warn("No default JNDI Binding Policy Defined (see ejb3-interceptors-aop.xml for example); defaulting to "
               + policyClass.getName());
         policy = policyClass;
      }
     
      // Log
      log.debug("Obtaining JNDI name from policy " + policy.getName());

      try
      {
         // Instanciate the policy and return
         return policy.newInstance();
      }
      catch (InstantiationException e)
      {
         throw new RuntimeException("Could not instanciate JNDI Binding Policy: " + policy.getName(), e);
      }
      catch (IllegalAccessException e)
      {
         throw new RuntimeException(e);
      }
   }

   private static EjbDeploymentSummary getDeploymentSummaryFromContainer(EJBContainer container)
   {
      // Construct Deployment Summary
      EjbDeploymentSummary summary = new EjbDeploymentSummary();
      summary.setEjbName(container.getEjbName());
      summary.setService(container instanceof ServiceContainer);
      summary.setStateful(container instanceof StatefulContainer);
      summary.setDeploymentName(container.getDeployment().getName());
      summary.setBeanClassName(container.getBeanClass().getName());
      DeploymentScope scope = container.getDeployment().getEar();
      if (scope != null)
      {
         summary.setDeploymentScopeBaseName(scope.getBaseName());
      }

      // Return
      return summary;
   }
}
TOP

Related Classes of org.jboss.ejb3.proxy.factory.ProxyFactoryHelper

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.