Package org.jboss.ejb3.interceptor

Source Code of org.jboss.ejb3.interceptor.InterceptorInfoRepository$SignatureValidator

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

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.CreateException;
import javax.ejb.PostActivate;
import javax.ejb.PrePassivate;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;

import org.jboss.ejb3.EJBContainer;
import org.jboss.logging.Logger;
import org.jboss.metadata.ejb.jboss.JBossMetaData;
import org.jboss.metadata.ejb.spec.AroundInvokeMetaData;
import org.jboss.metadata.ejb.spec.AroundInvokesMetaData;
import org.jboss.metadata.ejb.spec.InterceptorBindingMetaData;
import org.jboss.metadata.ejb.spec.InterceptorBindingsMetaData;
import org.jboss.metadata.ejb.spec.InterceptorMetaData;
import org.jboss.metadata.ejb.spec.InterceptorOrderMetaData;
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.LifecycleCallbackMetaData;
import org.jboss.metadata.javaee.spec.LifecycleCallbacksMetaData;

/**
* A repository of interceptor details shared amongst all containers in this deployment.
* Interceptors differ from other ejb 3 artifacts in that we can have annotations on the
* interceptor classes which are not the ejb container, so we cannot use annotation overrides
* on the interceptors themselves.<BR/>
* <BR/>
* The xml structures get added on deployment.<BR/>
* Interceptors only declared by using @Interceptors on the bean class get added on demand.<BR/>
*
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
* @version $Revision: 70409 $
* @deprecated  use the new interceptors component
*/
@Deprecated
public class InterceptorInfoRepository
{
   private static Logger log = Logger.getLogger(InterceptorInfoRepository.class);

   private ClassLoader classLoader;
  
   private Set<String> beanClasses = new HashSet<String>();

   private InterceptorsMetaData interceptorsXml;

   private InterceptorBindingsMetaData bindingsXml;

   private ConcurrentMap<Class<?>, InterceptorInfo> infos = new ConcurrentHashMap<Class<?>, InterceptorInfo>();

   private ConcurrentMap<String, InterceptorInfo> ejbInfos = new ConcurrentHashMap<String, InterceptorInfo>();

   private LinkedHashSet<InterceptorInfo> defaultInterceptors = null;
  
   private InterceptorSorter sorter = new InterceptorSorter();

   public InterceptorInfoRepository(ClassLoader classLoader)
   {
      assert classLoader != null : "classLoader is null";
     
      this.classLoader = classLoader;
   }

   public void initialise(JBossMetaData dd)
   {
      this.interceptorsXml = dd.getInterceptors();

      if (dd.getAssemblyDescriptor() != null)
      {
         this.bindingsXml = dd.getAssemblyDescriptor().getInterceptorBindings();
      }
     
      initialiseInfosFromXml();
      initialiseDefaultInterceptors();
   }

   public void addBeanClass(String classname)
   {
      beanClasses.add(classname);
   }

   public InterceptorInfo getInterceptorInfo(Class clazz)
   {
      initialiseInfosFromXml();
      return infos.get(clazz);
   }

   public HashSet<InterceptorInfo> getDefaultInterceptors()
   {
      return defaultInterceptors;
   }

   public boolean hasDefaultInterceptors()
   {
      return defaultInterceptors.size() > 0;
   }

   /*
   public ArrayList<InterceptorInfo> getClassInterceptors(EJBContainer container)
   {
      javax.interceptor.Interceptors interceptors = (javax.interceptor.Interceptors) container
            .resolveAnnotation(javax.interceptor.Interceptors.class);
      ArrayList<InterceptorInfo> infos = getInterceptorsFromAnnotation(container, interceptors);

      return infos;
   }
   */
  
   public ArrayList<InterceptorInfo> getMethodInterceptors(EJBContainer container, Method m)
   {
      javax.interceptor.Interceptors interceptors = (javax.interceptor.Interceptors) container.resolveAnnotation(m,
            javax.interceptor.Interceptors.class);
      ArrayList<InterceptorInfo> infos = getInterceptorsFromAnnotation(container, interceptors);

      return infos;
   }

   public Method[] getBeanClassAroundInvokes(EJBContainer container)
   {
      return getBeanClassInterceptors(container, AroundInvoke.class);
   }

   public Method[] getBeanClassPostConstructs(EJBContainer container)
   {
      return getBeanClassInterceptors(container, PostConstruct.class);
   }

   public Method[] getBeanClassPostActivates(EJBContainer container)
   {
      return getBeanClassInterceptors(container, PostActivate.class);
   }

   public Method[] getBeanClassPrePassivates(EJBContainer container)
   {
      return getBeanClassInterceptors(container, PrePassivate.class);
   }

   public Method[] getBeanClassPreDestroys(EJBContainer container)
   {
      return getBeanClassInterceptors(container, PreDestroy.class);
   }

   private Method[] getBeanClassInterceptors(EJBContainer container, Class type)
   {
      InterceptorInfo info = getOrInitialiseFromAnnotations(container);
      return getMethodsForEvent(info, type);
   }

   /*
   public InterceptorInfo[] getBusinessInterceptors(EJBContainer container, Method method)
   {
      return getInterceptors(container, AroundInvoke.class, method);
   }

   public InterceptorInfo[] getPostConstructInterceptors(EJBContainer container)
   {
      return getInterceptors(container, PostConstruct.class, null);
   }

   public InterceptorInfo[] getPostActivateInterceptors(EJBContainer container)
   {
      return getInterceptors(container, PostActivate.class, null);
   }

   public InterceptorInfo[] getPrePassivateInterceptors(EJBContainer container)
   {
      return getInterceptors(container, PrePassivate.class, null);
   }

   public InterceptorInfo[] getPreDestroyInterceptors(EJBContainer container)
   {
      return getInterceptors(container, PreDestroy.class, null);
   }
   */
  
   /*
   private InterceptorInfo[] getInterceptors(EJBContainer container, Class type, Method method)
   {
      ArrayList<InterceptorInfo> interceptors = new ArrayList<InterceptorInfo>();

      if (!hasAnnotation(container, ExcludeDefaultInterceptors.class, method))
      {
         HashSet<InterceptorInfo> infos = getDefaultInterceptors();
         if (infos != null)
         {
            interceptors.addAll(trimUnwanted(infos, type));
         }
         sorter.sortDefaultInterceptors(container, interceptors);
      }

     
      if (!hasAnnotation(container, ExcludeClassInterceptors.class, method))
      {
         List<InterceptorInfo> infos = container.getClassInterceptors();
         if (infos != null)
         {
            interceptors.addAll(trimUnwanted(infos, type));
         }
        
         if (type != AroundInvoke.class)
         {
            List<InterceptorInfo> methodOnlyInterceptors = getMethodOnlyInterceptorsForLifecycle(container, type, interceptors);
            if (infos != null)
               interceptors.addAll(methodOnlyInterceptors);
         }
         sorter.sortClassInterceptors(container, interceptors);
      }

      if (type == AroundInvoke.class)
      {
         List<InterceptorInfo> infos = getMethodInterceptors(container, method);
         if (infos != null)
            interceptors.addAll(trimUnwanted(infos, type));
         sorter.sortMethodInterceptors(container, method, interceptors);
      }

      InterceptorInfo[] ints = interceptors.toArray(new InterceptorInfo[interceptors.size()]);
      return ints;
   }
   */
  
   /*
   private List<InterceptorInfo> getMethodOnlyInterceptorsForLifecycle(EJBContainer container, Class type, List<InterceptorInfo> infos)
   {
      HashSet<InterceptorInfo> methodLevelInterceptors = (HashSet<InterceptorInfo>)container.getApplicableInterceptors().clone();
     
      for (InterceptorInfo info : infos)
      {
         if (methodLevelInterceptors.contains(info))
         {
            methodLevelInterceptors.remove(info);
         }
      }
     
      if (defaultInterceptors != null)
      {
         for (InterceptorInfo info : defaultInterceptors)
         {
            if (methodLevelInterceptors.contains(info))
            {
               methodLevelInterceptors.remove(info);
            }
         }
      }
     
      List<InterceptorInfo> trimmedInfos = trimUnwanted(methodLevelInterceptors, type);
      return trimmedInfos;
   }
   */
  
   /*
   private boolean hasAnnotation(EJBContainer container, Class annotation, Method method)
   {
      if (container.getAnnotation(annotation) != null)
      {
         return true;
      }

      if (method != null)
      {
         return container.resolveAnnotation(method, annotation) != null;
      }

      return false;
   }
   */
  
   private List<InterceptorInfo> trimUnwanted(Collection<InterceptorInfo> interceptors, Class type)
   {
      ArrayList<InterceptorInfo> ints = new ArrayList<InterceptorInfo>(interceptors.size());
      ints.addAll(interceptors);

      for (Iterator<InterceptorInfo> it = ints.iterator(); it.hasNext();)
      {
         InterceptorInfo info = it.next();
         if (!hasMethodsForEvent(info, type))
         {
            it.remove();
         }
      }

      return ints;
   }

   private boolean hasMethodsForEvent(InterceptorInfo info, Class type)
   {
      return getMethodsForEvent(info, type) != null;
   }
  
   private Method[] getMethodsForEvent(InterceptorInfo info, Class type)
   {
      if (type == AroundInvoke.class)
         return info.getAroundInvokes();
      else if (type == PostConstruct.class)
         return info.getPostConstructs();
      else if (type == PostActivate.class)
         return info.getPostActivates();
      else if (type == PrePassivate.class)
         return info.getPrePassivates();
      else if (type == PreDestroy.class)
         return info.getPreDestroys();
      return null;
   }

   private ArrayList<InterceptorInfo> getInterceptorsFromAnnotation(EJBContainer container,
         javax.interceptor.Interceptors interceptors)
   {
      ArrayList<InterceptorInfo> inters = new ArrayList<InterceptorInfo>();
      if (interceptors == null)
         return inters;

      for (Class clazz : interceptors.value())
      {
         InterceptorInfo info = getOrInitialiseFromAnnotations(clazz);
         validateInterceptorForContainer(container, info.getClazz());
         inters.add(info);
      }

      return inters;
   }

   private void validateInterceptorForContainer(EJBContainer container, Class interceptor)
   {
      if (beanClasses.contains(interceptor.getName()))
      {
         if (!interceptor.equals(container.getClazz()))
         {
            throw new RuntimeException("Bean class " + interceptor.getName() + " cannot be used as an interceptor for "
                  + container.getEjbName());
         }
      }
   }

   private void initialiseInfosFromXml()
   {
      if (interceptorsXml != null)
      {
         //Initialise all interceptor entries so we know which classes we have xml for
         HashMap<String, AnnotationInitialiser> initialisers = new HashMap<String, AnnotationInitialiser>();
         for (InterceptorMetaData xml : interceptorsXml)
         {
            XmlInitialiser init = new XmlInitialiser(xml);
            initialisers.put(xml.getInterceptorClass(), init);
         }

         //Create entries recursively, top classes first so we get the method hierarchies        
         for (InterceptorMetaData xml : interceptorsXml)
         {
            String clazz = xml.getInterceptorClass();
            initialiseSuperClassesFirstFromXmlOrAnnotations(initialisers, clazz);
         }

      }
   }

   private InterceptorInfo initialiseSuperClassesFirstFromXmlOrAnnotations(
         HashMap<String, AnnotationInitialiser> initialisers, String superClassName)
   {
      if ("java.lang.Object".equals(superClassName))
      {
         return null;
      }

      AnnotationInitialiser initialiser = initialisers.get(superClassName);
      if (initialiser == null)
      {
         initialiser = new AnnotationInitialiser(superClassName, InterceptorSignatureValidator.instance);
         initialisers.put(initialiser.getClazz().getName(), initialiser);
      }
      InterceptorInfo superInfo = initialiseSuperClassesFirstFromXmlOrAnnotations(
            initialisers, initialiser.getClazz().getSuperclass().getName());

      InterceptorInfo info = initialiser.getInfo();
      info.calculateHierarchy(superInfo);
      infos.put(info.getClazz(), info);
      return info;
   }

   /*
    * Default interceptors are defined using xml only
    */
   private void initialiseDefaultInterceptors()
   {
      defaultInterceptors = new LinkedHashSet<InterceptorInfo>();

      if (bindingsXml != null)
      {
         for (InterceptorBindingMetaData bindingXml : bindingsXml)
         {
            if (bindingXml.getEjbName().equals("*") && bindingXml.getMethod() == null)
            {
               for (String classname : bindingXml.getInterceptorClasses())
               {
                  if (beanClasses.contains(classname))
                  {
                     throw new RuntimeException("Bean class defined in default binding " + classname);
                  }
                  InterceptorInfo info = getOrInitialiseFromAnnotations(classname);
                  defaultInterceptors.add(info);
               }
            }
         }
      }
   }

   private InterceptorInfo getOrInitialiseFromAnnotations(String classname)
   {
      Class clazz = loadClass(classname);
      return getOrInitialiseFromAnnotations(clazz);
   }

   private InterceptorInfo getOrInitialiseFromAnnotations(Class clazz)
   {
      InterceptorInfo info = infos.get(clazz);

      if (info == null)
      {
         synchronized (this)
         {
            info = infos.get(clazz);
            if (info == null)
            {
               info = initialiseFromAnnotations(clazz);
               infos.put(clazz, info);
            }
         }
      }

      return info;
   }

   private InterceptorInfo initialiseFromAnnotations(Class clazz)
   {
      InterceptorInfo superInfo = null;
      if (clazz.getSuperclass() != Object.class)
      {
         superInfo = getOrInitialiseFromAnnotations(clazz.getSuperclass());
      }

      AnnotationInitialiser init = new AnnotationInitialiser(clazz, InterceptorSignatureValidator.instance);
      InterceptorInfo info = init.getInfo();
      info.calculateHierarchy(superInfo);
      return info;
   }

   private InterceptorInfo getOrInitialiseFromAnnotations(EJBContainer container)
   {
      InterceptorInfo info = ejbInfos.get(container.getEjbName());

      if (info == null)
      {
         synchronized (this)
         {
            info = ejbInfos.get(container.getEjbName());
            if (info == null)
            {
               info = initialiseFromAnnotations(container);
               ejbInfos.put(container.getEjbName(), info);
            }
         }
      }

      return info;
   }

   private InterceptorInfo initialiseFromAnnotations(EJBContainer container)
   {
      //Currently I see no way in spec for specifying interceptors of an ejb super class using xml,
      //use annotations only to initialise super classes, and don't store these
      InterceptorInfo superInfo = initialiseContainerSuperClassFromAnnotationsOnly(container.getClazz().getSuperclass());
      AnnotationInitialiser init = new ContainerInitialiser(container);
      InterceptorInfo info = init.getInfo();
      info.calculateHierarchy(superInfo);
      return info;
   }

   private InterceptorInfo initialiseContainerSuperClassFromAnnotationsOnly(Class clazz)
   {
      InterceptorInfo superInfo = null;
      if (clazz != Object.class)
      {
         superInfo = initialiseContainerSuperClassFromAnnotationsOnly(clazz.getSuperclass());
      }

      AnnotationInitialiser init = new AnnotationInitialiser(clazz, BeanSignatureValidator.instance);
      InterceptorInfo info = init.getInfo();
      info.calculateHierarchy(superInfo);
      return info;
   }
  
  
   private Class<?> loadClass(String name)
   {
      try
      {
         if(log.isTraceEnabled())
            log.trace("Loading interceptor " + name + " from " + classLoader);
         return classLoader.loadClass(name);
      }
      catch (ClassNotFoundException e)
      {
         throw new RuntimeException("Interceptor class not found: " + name + " in class loader " + classLoader, e);
      }
   }

   private static boolean checkExceptions(Class<?> allowedExceptions[], Method method)
   {
      for(Class<?> exception : method.getExceptionTypes())
      {
         boolean isAllowed = false;
         for(Class<?> allowed : allowedExceptions)
         {
            if(allowed.isAssignableFrom(exception))
               isAllowed = true;
         }
         if(!isAllowed)
         {
            log.warn("Illegal exception '" + exception.getName() + "' in lifecycle signature (EJB3 12.4.2): " + method);
            return false;
         }
      }
      return true;
   }
  
   public static boolean checkValidBusinessSignature(Method method)
   {
      int modifiers = method.getModifiers();

      if (!Modifier.isStatic(modifiers))
      {
         if (method.getReturnType().equals(Object.class))
         {
            Class[] params = method.getParameterTypes();
            if (params.length == 1 && params[0].equals(InvocationContext.class))
            {
               Class[] exceptions = method.getExceptionTypes();
               if (exceptions.length == 1 && exceptions[0].equals(Exception.class))
               {
                  return true;
               }
            }
         }
      }
      return false;
   }

   public static boolean checkValidLifecycleSignature(Method method)
   {
      int modifiers = method.getModifiers();

      if (!Modifier.isStatic(modifiers))
      {
         if (method.getReturnType().equals(Void.TYPE))
         {
            Class[] params = method.getParameterTypes();
            if (params.length == 1 && params[0].equals(InvocationContext.class))
            {
               return true;
            }
         }
      }
      return false;
   }

   /**
    * EJB3 12.4
    * Lifecycle methods may throw runtime exceptions, but not application exceptions.
    * Note that for 2.1 beans CreateException (on ejbCreate) and RemoteException should pass.
    *
    * @param method
    * @return
    */
   public static boolean checkValidBeanLifecycleSignature(Method method)
   {
      int modifiers = method.getModifiers();
      if (method.getName().equals("ejbCreate"))
      {
         // for public void ejbCreate(...) throws javax.ejb.CreateException
         if (!Modifier.isStatic(modifiers) && method.getReturnType().equals(Void.TYPE)
               && method.getExceptionTypes().length <= 1)
         {
            if(!checkExceptions(new Class<?>[] { RuntimeException.class, CreateException.class, RemoteException.class }, method))
               return false;
            return true;
         }
      }
      else if (!Modifier.isStatic(modifiers) && method.getReturnType().equals(Void.TYPE)
            && method.getParameterTypes().length == 0)
      {
         if(!checkExceptions(new Class<?>[] { RuntimeException.class, RemoteException.class }, method))
            return false;
         return true;
      }
      return false;
   }

   public static String simpleType(Class type)
   {
      Class ret = type;
      if (ret.isArray())
      {
         Class arr = ret;
         String array = "";
         while (arr.isArray())
         {
            array += "[]";
            arr = arr.getComponentType();
         }
         return arr.getName() + array;
      }
      return ret.getName();
   }
  

   private interface SignatureValidator
   {
      boolean checkValidLifecycle(Method m);
      boolean checkValidAround(Method m);
   }

   private static class InterceptorSignatureValidator implements SignatureValidator
   {
      static SignatureValidator instance = new InterceptorSignatureValidator();
      public boolean checkValidAround(Method m)
      {
         return checkValidBusinessSignature(m);
      }

      public boolean checkValidLifecycle(Method m)
      {
         return checkValidLifecycleSignature(m);
      }
   }

   private static class BeanSignatureValidator implements SignatureValidator
   {
      static SignatureValidator instance = new BeanSignatureValidator();
      public boolean checkValidAround(Method m)
      {
         return checkValidBusinessSignature(m);
      }

      public boolean checkValidLifecycle(Method m)
      {
         return checkValidBeanLifecycleSignature(m);
      }
   }
  
  
   private class AnnotationInitialiser
   {
      SignatureValidator signatureValidator;
      Class clazz;

      InterceptorInfo info;

      AnnotationInitialiser(String classname, SignatureValidator signatureValidator)
      {
         clazz = loadClass(classname);
         this.signatureValidator = signatureValidator;
         info = new InterceptorInfo(clazz);
      }

      AnnotationInitialiser(Class clazz, SignatureValidator signatureValidator)
      {
         this.clazz = clazz;
         this.signatureValidator = signatureValidator;
         info = new InterceptorInfo(clazz);
      }

      public Class getClazz()
      {
         return clazz;
      }

      InterceptorInfo getInfo()
      {
         for (Method method : clazz.getDeclaredMethods())
         {
            info.setAroundInvoke(resolveAroundInvoke(method));
            info.setPostConstruct(resolvePostConstruct(method));
            info.setPostActivate(resolvePostActivate(method));
            info.setPreDestroy(resolvePreDestroy(method));
            info.setPrePassivate(resolvePrePassivate(method));
         }
         return info;
      }

      Method resolveAroundInvoke(Method method)
      {
         AroundInvoke ann = (AroundInvoke) getAnnotation(method, AroundInvoke.class);
         if (ann != null)
         {
            if (!signatureValidator.checkValidAround(method))
            {
               throw new RuntimeException("@" + ((Annotation) ann).annotationType().getName()
                     + " annotated method in has the wrong signature - " + method);
            }
            return method;
         }
         return null;
      }

      Method resolvePostConstruct(Method method)
      {
         PostConstruct ann = (PostConstruct) getAnnotation(method, PostConstruct.class);
         return resolveLifecycleMethod(method, ann);
      }

      Method resolvePostActivate(Method method)
      {
         PostActivate ann = (PostActivate) getAnnotation(method, PostActivate.class);
         return resolveLifecycleMethod(method, ann);
      }

      Method resolvePreDestroy(Method method)
      {
         PreDestroy ann = (PreDestroy) getAnnotation(method, PreDestroy.class);
         return resolveLifecycleMethod(method, ann);
      }

      Method resolvePrePassivate(Method method)
      {
         PrePassivate ann = (PrePassivate) getAnnotation(method, PrePassivate.class);
         return resolveLifecycleMethod(method, ann);
      }

      Method resolveLifecycleMethod(Method method, Annotation ann)
      {
         if (ann != null)
         {
            if (!signatureValidator.checkValidLifecycle(method))
            {
               throw new RuntimeException("@" + ((Annotation) ann).annotationType().getName()
                     + " annotated method  has the wrong signature - " + method);
            }
            return method;
         }
         return null;
      }

      Object getAnnotation(Method method, Class annotation)
      {
         return method.getAnnotation(annotation);
      }

   }

   private class ContainerInitialiser extends AnnotationInitialiser
   {
      EJBContainer container;

      public ContainerInitialiser(EJBContainer container)
      {
         // FIXME ContainerInitialiser constructor
         super(container.getBeanClass(), BeanSignatureValidator.instance);
         this.container = container;
      }

      Object getAnnotation(Method method, Class annotation)
      {
         return container.resolveAnnotation(method, annotation);
      }

      /*
       * Lifecycle methods on bean class have a different signature from those defined on
       *
       */
      Method resolveLifecycleMethod(Method method, Annotation ann)
      {
         if (ann != null)
         {
            if (!signatureValidator.checkValidLifecycle(method))
            {
               throw new RuntimeException("@" + ann.annotationType().getName()
                       + " annotated method has the wrong signature - " + method + " (EJB3 12.4)");
            }
            return method;
         }
         return null;
      }
   }

   private class XmlInitialiser extends AnnotationInitialiser
   {
      InterceptorMetaData xml;

      XmlInitialiser(InterceptorMetaData xml)
      {
         super(xml.getInterceptorClass(), InterceptorSignatureValidator.instance);
         this.xml = xml;
      }

      InterceptorInfo getInfo()
      {
         info.setAroundInvoke(findInterceptorMethodFromXml("around-invoke-method", xml.getAroundInvokes()));
         info.setPostConstruct(findInterceptorMethodFromXml("post-construct-method", xml.getPostConstructs()));
         info.setPostActivate(findInterceptorMethodFromXml("post-activate-method", xml.getPostActivates()));
         info.setPreDestroy(findInterceptorMethodFromXml("pre-destroy-method", xml.getPreDestroys()));
         info.setPrePassivate(findInterceptorMethodFromXml("pre-passivate-method", xml.getPrePassivates()));
         super.getInfo();
         info.setXml(xml);
         return info;
      }

      Method findInterceptorMethodFromXml(String lookingFor, AroundInvokesMetaData aroundInvokes)
      {
         if (aroundInvokes == null)
            return null;
         if(aroundInvokes.size() != 1)
            throw new RuntimeException("NYI");
        
         AroundInvokeMetaData aroundInvoke = aroundInvokes.get(0);
         return findInterceptorMethodFromXml(lookingFor, aroundInvoke.getClassName(), aroundInvoke.getMethodName());
      }
     
      Method findInterceptorMethodFromXml(String lookingFor, LifecycleCallbacksMetaData lifecycleCallbacks)
      {
         if (lifecycleCallbacks == null)
            return null;
         if(lifecycleCallbacks.size() != 1)
            throw new RuntimeException("NYI");
        
         LifecycleCallbackMetaData lifecycleCallback = lifecycleCallbacks.get(0);
         return findInterceptorMethodFromXml(lookingFor, lifecycleCallback.getClassName(), lifecycleCallback.getMethodName());
      }
     
      Method findInterceptorMethodFromXml(String lookingFor, String className, String methodName)
      {
         if (xml == null)
            return null;
        
         // If a class name is specified look in there, else in the surrounding class
         Class<?> cls;
         if(className == null)
            cls = clazz;
         else
            cls = loadClass(className);
        
         if (methodName == null || methodName.trim().equals(""))
         {
            throw new RuntimeException(lookingFor + " must contain a valid method name for interceptor "
                  + clazz.getName());
         }

         List<Method> possible = new ArrayList<Method>();
         for (java.lang.reflect.Method method : cls.getDeclaredMethods())
         {
            if (methodName.equals(method.getName()))
            {
               possible.add(method);
            }
         }

         if (possible.size() == 0)
         {
            throw new RuntimeException(lookingFor + " can't find method " + methodName + " on " + cls.getName());
         }

         Method found = null;

         for (Method method : possible)
         {
            // TODO: barf, use a validator as parameter
            if (lookingFor.equals("around-invoke-method"))
            {
               if (signatureValidator.checkValidAround(method))
               {
                  found = method;
               }
            }
            else
            {
               if (signatureValidator.checkValidLifecycle(method))
               {
                  found = method;
               }
            }
         }

         if (found == null)
         {
            // TODO: improve error message
            throw new RuntimeException(lookingFor + " has the wrong method signature for interceptor "
                  + clazz.getName());
         }

         return found;
      }
   }

   private class InterceptorSorter
   {
      boolean initialised;
      List<InterceptorBindingMetaData> orderedBindings;
     
      private void initialise()
      {
         if (!initialised)
         {
            synchronized(this)
            {
               if (bindingsXml != null)
               {
                  for (InterceptorBindingMetaData binding : bindingsXml)
                  {
                     if (binding.isTotalOrdering())
                     {
                        //Validate each interceptor only occurs once
                        HashSet<String> names = new HashSet<String>();
                        for(String className : binding.getInterceptorOrder())
                        {
                           if (names.contains(className))
                           {
                              throw new RuntimeException(className + " occurs more than once in ordered binding " +
                                    getInterceptorBindingString(binding));
                           }
                           names.add(className);
                        }
                       
                        if (orderedBindings == null)
                        {
                           orderedBindings = new ArrayList<InterceptorBindingMetaData>();
                        }
                        orderedBindings.add(binding);
                     }
                  }
               }
            }
            log.trace("orderedBindings = " + orderedBindings);
            initialised = true;
         }
      }
     
      void sortDefaultInterceptors(EJBContainer container, ArrayList<InterceptorInfo> infos)
      {
         initialise();
         if (orderedBindings == nullreturn;
         InterceptorOrderMetaData bindingOrder = null;
         for (InterceptorBindingMetaData binding : orderedBindings)
         {
            if (binding.getEjbName().equals("*"))
            {
               if (bindingOrder != null)
               {
                  throw new RuntimeException("There should only be one interceptor-binding specifying " +
                        "the order of default interceptors " + getInterceptorBindingString(binding));
               }
               bindingOrder = binding.getInterceptorOrder();
            }
         }
         sortInterceptors(infos, bindingOrder);
      }
     
      void sortClassInterceptors(EJBContainer container, ArrayList<InterceptorInfo> infos)
      {
         initialise();
         if (orderedBindings == nullreturn;
         InterceptorOrderMetaData bindingOrder = null;
         for (InterceptorBindingMetaData binding : orderedBindings)
         {
            if(binding.getMethod() != null)
               continue;
            if (binding.getEjbName().equals(container.getEjbName()))
            {
               if (bindingOrder != null)
               {
                  throw new RuntimeException("There should only be one interceptor-binding specifying " +
                        "the order of class interceptors: " + getInterceptorBindingString(binding));
               }
               bindingOrder = binding.getInterceptorOrder();
            }
         }
         sortInterceptors(infos, bindingOrder);
      }
     
      void sortMethodInterceptors(EJBContainer container, Method method, ArrayList<InterceptorInfo> infos)
      {
         initialise();
         if (orderedBindings == nullreturn;
         InterceptorOrderMetaData methodNoParamsOrder = null;
         InterceptorOrderMetaData methodParamsOrder = null;
         for (InterceptorBindingMetaData binding : orderedBindings)
         {
            if (binding.getEjbName().equals(container.getEjbName()))
            {
               NamedMethodMetaData bindingMethod = binding.getMethod();
               if (bindingMethod != null)
               {
                  if (bindingMethod.getMethodParams() == null)
                  {
                     if (methodNoParamsOrder != null)
                     {
                        throw new RuntimeException("There should only be one interceptor-binding specifying " +
                              "the order of method interceptors: "  + getInterceptorBindingString(binding));
                     }
                     methodNoParamsOrder = binding.getInterceptorOrder();
                  }
                  else
                  {
                     Class<?>[] params = method.getParameterTypes();
                     List<String> methodParams = bindingMethod.getMethodParams();
                     if (methodParams.size() == params.length)
                     {
                        boolean matches = true;
                        for (int i = 0 ; i < params.length ; i++)
                        {
                           if (!simpleType(params[i]).equals(methodParams.get(i)))
                           {
                              matches = false;
                              break;
                           }
                        }
                       
                        if (matches)
                        {
                           if (methodParamsOrder != null)
                           {
                              boolean first = false;
                              StringBuffer paramBuf = new StringBuffer();
                              paramBuf.append("(");
                              for (String par : methodParams)
                              {
                                 if (!first) paramBuf.append(",");
                                 paramBuf.append(par);
                              }
                              paramBuf.append(")");
                              throw new RuntimeException("There should only be one interceptor-binding specifying " +
                                    "the order of method interceptors: " + getInterceptorBindingString(binding));
                           }
                          
                           methodParamsOrder = binding.getInterceptorOrder();
                        }
                     }
                  }
               }
            }
         }
        
         if (methodParamsOrder != null)
         {
            sortInterceptors(infos, methodParamsOrder);
           
         }
         else
         {
            sortInterceptors(infos, methodNoParamsOrder);
         }
      }
     
      void sortInterceptors(ArrayList<InterceptorInfo> infos, InterceptorOrderMetaData interceptorOrder)
      {
         if (interceptorOrder == null) return;
         Collections.sort(infos, new InterceptorComparator(interceptorOrder));
      }

      String getInterceptorBindingString(InterceptorBindingMetaData binding)
      {
         StringBuffer buf = new StringBuffer();
        
         buf.append(binding.getEjbName());
         NamedMethodMetaData method = binding.getMethod();
         if(method != null)
         {
            buf.append("." + method.getMethodName());
            MethodParametersMetaData methodParams = method.getMethodParams();
            if (methodParams != null)
            {
               buf.append("(");
               for (int i = 0 ; i < methodParams.size() ; )
               {
                  if (i == 0) buf.append(",");
                  buf.append(methodParams.get(i));
               }
               buf.append(")");
            }
         }
        
         return buf.toString();
      }
   }
  
   private class InterceptorComparator implements Comparator<InterceptorInfo>
   {
      List<String> ordered;

      InterceptorComparator(InterceptorOrderMetaData ordered)
      {
         assert ordered != null : "ordered is null";
        
         this.ordered = new ArrayList<String>(ordered);
      }
     
      public int compare(InterceptorInfo o1, InterceptorInfo o2)
      {
         int pos1 = ordered.indexOf(o1.getClazz().getName());
         int pos2 = ordered.indexOf(o2.getClazz().getName());
        
         //Make anything not specified in the order come last
         if (pos1 < 0) pos1 = Integer.MAX_VALUE;
         if (pos2 < 0) pos2 = Integer.MAX_VALUE;
        
         if (pos1 < pos2)
         {
            return -1;
         }
         else if (pos1 > pos2)
         {
            return 1;
         }
         else
         {
            return 0;
         }
      }
     
     
   }
  
}
TOP

Related Classes of org.jboss.ejb3.interceptor.InterceptorInfoRepository$SignatureValidator

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.