All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.interceptor.reader.InterceptorMetadataUtils Maven / Gradle / Ivy

There is a newer version: 3.0.0.Alpha1
Show newest version
package org.jboss.interceptor.reader;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.interceptor.InvocationContext;

import org.jboss.interceptor.builder.MethodReference;
import org.jboss.interceptor.spi.metadata.ClassMetadata;
import org.jboss.interceptor.spi.metadata.InterceptorMetadata;
import org.jboss.interceptor.spi.metadata.InterceptorReference;
import org.jboss.interceptor.spi.metadata.MethodMetadata;
import org.jboss.interceptor.spi.model.InterceptionType;
import org.jboss.interceptor.util.InterceptionTypeRegistry;
import org.jboss.interceptor.util.InterceptorMetadataException;
import org.jboss.interceptor.util.ReflectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Marius Bogoevici
 */
public class InterceptorMetadataUtils
{
   protected static final String OBJECT_CLASS_NAME = Object.class.getName();

   private static final Logger LOG = LoggerFactory.getLogger(InterceptorMetadataUtils.class);


   public static InterceptorMetadata readMetadataForInterceptorClass(InterceptorReference interceptorReference)
   {
      return new SimpleInterceptorMetadata(interceptorReference, false, buildMethodMap(interceptorReference.getClassMetadata(), false));
   }

   public static InterceptorMetadata readMetadataForTargetClass(ClassMetadata classMetadata)
   {
      return new SimpleInterceptorMetadata(ClassMetadataInterceptorReference.of(classMetadata), true, buildMethodMap(classMetadata, true));
   }

   public static boolean isInterceptorMethod(InterceptionType interceptionType, MethodMetadata method, boolean forTargetClass)
   {

      if (!method.getSupportedInterceptionTypes().contains(interceptionType))
      {
         return false;
      }

      if (interceptionType.isLifecycleCallback())
      {
         if (!Void.TYPE.equals(method.getReturnType()))
         {
            if (LOG.isWarnEnabled())
            {
              LOG.warn(getStandardIgnoredMessage(interceptionType, method.getJavaMethod()) + "does not have a void return type");
            }
            return false;
         }

         Class[] parameterTypes = method.getJavaMethod().getParameterTypes();

         if (forTargetClass && parameterTypes.length != 0)
         {
            if (LOG.isWarnEnabled())
            {
               LOG.warn(getStandardIgnoredMessage(interceptionType, method.getJavaMethod()) + "is defined on the target class and does not have 0 arguments");
            }
            return false;
         }

         if (!forTargetClass && parameterTypes.length != 1)
         {
            if (LOG.isWarnEnabled())
            {
               LOG.warn(getStandardIgnoredMessage(interceptionType, method.getJavaMethod()) + "does not have exactly one parameter");
            }
            return false;
         }

         if (parameterTypes.length == 1 && !InvocationContext.class.isAssignableFrom(parameterTypes[0]))
         {
            if (LOG.isWarnEnabled())
            {
               LOG.warn(getStandardIgnoredMessage(interceptionType, method.getJavaMethod()) + "its single argument is not a " + InvocationContext.class.getName());
            }
            return false;
         }

         return true;
      }
      else
      {
         if (!Object.class.equals(method.getReturnType()))
         {
            if (LOG.isWarnEnabled())
            {
               LOG.warn(getStandardIgnoredMessage(interceptionType, method.getJavaMethod()) + "does not return a " + OBJECT_CLASS_NAME);
            }
            return false;
         }

         Class[] parameterTypes = method.getJavaMethod().getParameterTypes();

         if (parameterTypes.length != 1)
         {
            if (LOG.isWarnEnabled())
            {
               LOG.debug(getStandardIgnoredMessage(interceptionType, method.getJavaMethod()) + "does not have exactly 1 parameter");
            }
            return false;
         }

         if (!InvocationContext.class.isAssignableFrom(parameterTypes[0]))
         {
            if (LOG.isWarnEnabled())
            {
               LOG.debug(getStandardIgnoredMessage(interceptionType, method.getJavaMethod()) + "does not have a " + InvocationContext.class.getName() + " parameter ");
            }
            return false;
         }

         return true;
      }
   }

   static String getStandardIgnoredMessage(InterceptionType interceptionType, Method method)
   {
      return "Method " + method.getName() + " defined on class " + method.getDeclaringClass().getName()
            + " will not be used for interception, since it is not defined according to the specification. It is annotated with @"
            + interceptionType.annotationClassName() + ", but ";
   }

   static Map> buildMethodMap(ClassMetadata interceptorClass, boolean forTargetClass)
   {
      Map> methodMap = new HashMap>();
      ClassMetadata currentClass = interceptorClass;
      Set foundMethods = new HashSet();
      do
      {
         Set detectedInterceptorTypes = new HashSet();

         for (MethodMetadata method : currentClass.getDeclaredMethods())
         {
            MethodReference methodReference = MethodReference.of(method, Modifier.isPrivate(method.getJavaMethod().getModifiers()));
            if (!foundMethods.contains(methodReference))
            {
               for (InterceptionType interceptionType : InterceptionTypeRegistry.getSupportedInterceptionTypes())
               {
                  if (isInterceptorMethod(interceptionType, method, forTargetClass))
                  {
                     if (methodMap.get(interceptionType) == null)
                     {
                        methodMap.put(interceptionType, new LinkedList());
                     }
                     if (detectedInterceptorTypes.contains(interceptionType))
                     {
                        throw new InterceptorMetadataException("Same interception type cannot be specified twice on the same class");
                     }
                     else
                     {
                        detectedInterceptorTypes.add(interceptionType);
                     }
                     // add method in the list - if it is there already, it means that it has been added by a subclass
                     // final methods are treated separately, as a final method cannot override another method nor be
                     // overridden
                     ReflectionUtils.ensureAccessible(method.getJavaMethod());
                     if (!foundMethods.contains(methodReference));
                     {
                        methodMap.get(interceptionType).add(0, method);
                     }
                  }
               }
               // the method reference must be added anyway - overridden methods are not taken into consideration
               foundMethods.add(methodReference);
            }
         }
         currentClass = currentClass.getSuperclass();
      }
      while (currentClass != null && !OBJECT_CLASS_NAME.equals(currentClass.getJavaClass()));
      return methodMap;
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy