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

org.jboss.spring.aop.JBossAopProxy Maven / Gradle / Ivy

The newest version!
/*
 * 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.spring.aop;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.security.AccessController;
import java.security.PrivilegedAction;

import org.jboss.aop.Advisor;
import org.jboss.aop.AspectManager;
import org.jboss.aop.advice.Interceptor;
import org.jboss.aop.joinpoint.ConstructorInvocation;
import org.jboss.aop.proxy.container.AOPProxyFactory;
import org.jboss.aop.proxy.container.AOPProxyFactoryParameters;
import org.jboss.aop.proxy.container.ContainerCache;
import org.jboss.aop.proxy.container.GeneratedAOPProxyFactory;
import org.jboss.joinpoint.plugins.Config;
import org.jboss.metadata.spi.MetaData;
import org.jboss.metadata.spi.scope.CommonLevels;
import org.jboss.metadata.spi.scope.CommonLevelsUtil;
import org.jboss.metadata.spi.scope.ScopeLevel;
import org.jboss.metadata.spi.signature.DeclaredMethodSignature;
import org.jboss.metadata.spi.stack.MetaDataStack;
import org.jboss.reflect.spi.ClassInfo;
import org.jboss.reflect.spi.ConstructorInfo;
import org.jboss.reflect.spi.MethodInfo;
import org.jboss.reflect.spi.TypeInfo;
import org.jboss.config.spi.Configuration;
import org.jboss.config.plugins.property.PropertyConfiguration;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;

/**
 * JBoss based AOP proxy.
 *
 * @author Ales Justin
 */
public class JBossAopProxy implements AopProxy
{
   /** The configuration */
   private static Configuration configuration;
   private static final List levels;

   static
   {
      // get Configuration instance
      configuration = AccessController.doPrivileged(new PrivilegedAction()
      {
         public Configuration run()
         {
            return new PropertyConfiguration();
         }
      });

      // get all sub INSTANCE levels
      levels = new ArrayList(CommonLevelsUtil.getSubLevels(CommonLevels.INSTANCE));
      // remove class joinpoint, we're only interested in instance/joinpoint_override
      levels.remove(CommonLevels.JOINPOINT);
   }

   private AdvisedSupport config;
   private AOPProxyFactory proxyFactory = new GeneratedAOPProxyFactory();
   private ConstructorInfo constructorInfo;

   public JBossAopProxy(AdvisedSupport config)
   {
      if (config == null)
         throw new IllegalArgumentException("Null config");

      this.config = config;
   }

   public Object getProxy()
   {
      return getProxy(null);
   }

   public Object getProxy(ClassLoader classLoader)
   {
      Class clazz = config.getTargetClass();
      if (clazz == null)
         throw new IllegalArgumentException("Null target class");

      try
      {
         ClassInfo classInfo = configuration.getClassInfo(clazz);
         constructorInfo = Config.findConstructorInfo(classInfo, new String[]{}); // TODO - arguments

         MetaData metaData = MetaDataStack.peek();
         boolean hasInstanceMetaData = rootHasSubInstanceMetaData(metaData);
         AspectManager manager = AspectManagerFactory.getAspectManager(metaData);
         ContainerCache cache = ContainerCache.initialise(manager, clazz, metaData, hasInstanceMetaData);
         AOPProxyFactoryParameters params = new AOPProxyFactoryParameters();

         Object target = null;
         TargetSource ts = config.getTargetSource();
         if (ts != null)
            target = ts.getTarget();

         if (target == null)
               target = createTarget(cache, params);

         params.setProxiedClass(target.getClass());
         params.setMetaData(metaData);
         params.setTarget(target);
         params.setContainerCache(cache);
         params.setMetaDataHasInstanceLevelData(hasInstanceMetaData);

         return proxyFactory.createAdvisedProxy(params);
      }
      catch (Throwable t)
      {
         throw new RuntimeException(t);  
      }
   }

   /**
    * Check for metadata at INSTANCE level and below.
    *
    * @param metaData the metadata
    * @return true if there is some metadata that needs to be considered
    */
   private boolean rootHasSubInstanceMetaData(MetaData metaData)
   {
      if (metaData == null)
      {
         return false;
      }

      if (checkForMetaDataAtSubInstanceLevel(metaData))
      {
         return true;
      }

      //Check for method annotations
      return rootHasMethodWithSubInstanceMetaData(metaData);
   }

   /**
    * Check for metadata at INSTANCE level and below for methods.
    *
    * @param metaData the metadata
    * @return true if there is some metadata that needs to be considered
    */
   private boolean rootHasMethodWithSubInstanceMetaData(MetaData metaData)
   {
      //Check for method annotations
      ClassInfo info = constructorInfo.getDeclaringClass();
      while (info != null)
      {
         MethodInfo[] methods = info.getDeclaredMethods();
         if (methods != null)
         {
            for (MethodInfo mi : methods)
            {
               if (methodHasSubInstanceMetaData(metaData, mi))
               {
                  return true;
               }
            }
         }
         info = info.getSuperclass();
      }

      return false;
   }

   /**
    * Check for metadata at INSTANCE level and below for methods.
    *
    * @param metaData the metadata
    * @param mi the method to check
    * @return true if there is some metadata that needs to be considered
    */
   private boolean methodHasSubInstanceMetaData(MetaData metaData, MethodInfo mi)
   {
      DeclaredMethodSignature sig = new DeclaredMethodSignature(mi);
      MetaData methodMD = metaData.getComponentMetaData(sig);
      return checkForMetaDataAtSubInstanceLevel(methodMD);
   }

   /**
    * Check for metadata at INSTANCE level and below.
    *
    * @param metaData the metadata
    * @return true if there is some metadata that needs to be considered
    */
   private boolean checkForMetaDataAtSubInstanceLevel(MetaData metaData)
   {
      if (metaData != null)
      {
         for (ScopeLevel level : levels)
         {
            if (hasMetaDataAtLevel(metaData, level))
               return true;
         }
      }
      return false;
   }

   /**
    * Check for metadata at level param.
    *
    * @param metaData the metadata
    * @param level the scope level
    * @return true if there is some metadata that needs to be considered
    */
   protected boolean hasMetaDataAtLevel(MetaData metaData, ScopeLevel level)
   {
      MetaData levelMetaData = metaData.getScopeMetaData(level);
      if (levelMetaData != null && levelMetaData.isEmpty() == false)
      {
         Object[] allMetaData = levelMetaData.getMetaData();
         Annotation[] annotations = levelMetaData.getAnnotations();
         // all meta data is not null, since level metadata is not empty
         int allSize = allMetaData.length;
         int annotationsSize = annotations != null ? annotations.length : 0;

         // do we have something else than annotations
         if (allSize > annotationsSize)
         {
            return true;
         }
         else if (annotationsSize > 0)
         {
            return true;
         }
      }
      return false;
   }

   /**
    * Create the target.
    *
    * @param cache the cache
    * @param params the parameters
    * @return target instance
    * @throws Throwable for any error
    */
   private Object createTarget(ContainerCache cache, AOPProxyFactoryParameters params) throws Throwable
   {
      Advisor advisor = cache.getAdvisor();
      if (advisor != null)
      {
         org.jboss.aop.ConstructorInfo aopinfo = findAopConstructorInfo(advisor);

         Interceptor[] interceptors = (aopinfo != null) ? aopinfo.getInterceptors() : null;

         if (interceptors != null)
         {
            ConstructorInvocation inv = new ConstructorInvocation(aopinfo, aopinfo.getInterceptors());
            inv.setArguments(getArguments());
            return inv.invokeNext();
         }

         if (constructorInfo.getParameterTypes().length > 0)
         {
            Constructor constructor = null;
            if (aopinfo == null)
            {
               //Fall back to using the class;
               Class clazz = advisor.getClazz();
               Constructor[] ctors = clazz.getConstructors();
               for (Constructor ctor : ctors)
               {
                  if (matchConstructor(ctor))
                  {
                     constructor = ctor;
                     break;
                  }
               }
            }
            else
            {
               constructor = aopinfo.getConstructor();
            }
            params.setCtor(constructor.getParameterTypes(), getArguments());
         }
      }

      return constructorInfo.newInstance(getArguments());
   }

   /**
    * Find constructor info.
    *
    * @param advisor the advisor
    * @return matched constructor or null if no match
    */
   private org.jboss.aop.ConstructorInfo findAopConstructorInfo(Advisor advisor)
   {
      org.jboss.aop.ConstructorInfo[] infos = advisor.getConstructorInfos();
      for (int i = 0 ; i < infos.length ; i++)
      {
         if (matchConstructor(infos[i].getConstructor()))
         {
            return infos[i];
         }
      }
      return null;
   }

   /**
    * Match constructor.
    *
    * @param ctor the constructor
    * @return true if we have a match
    */
   private boolean matchConstructor(Constructor ctor)
   {
      TypeInfo[] params = constructorInfo.getParameterTypes();
      Class[] ctorParams = ctor.getParameterTypes();
      if (params.length == ctorParams.length)
      {
         boolean match = true;
         for (int p = 0 ; p < params.length ; p++)
         {
            if (!params[p].getName().equals(ctorParams[p].getName()))
            {
               match = false;
               break;
            }
         }

         if (match)
         {
            return true;
         }
      }
      return false;
   }

   protected Object[] getArguments()
   {
      return new Object[]{}; // TODO - proper arguments
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy