org.jboss.spring.aop.JBossAopProxy.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.spring.aop.JBossAopProxy.java

Source

/*
 * 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 <a href="mailto:ales.justin@jboss.org">Ales Justin</a>
 */
public class JBossAopProxy implements AopProxy {
    /** The configuration */
    private static Configuration configuration;
    private static final List<ScopeLevel> levels;

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

        // get all sub INSTANCE levels
        levels = new ArrayList<ScopeLevel>(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()) {
            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
    }
}