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

org.apache.deltaspike.proxy.api.DeltaSpikeProxyFactory Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.deltaspike.proxy.api;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.enterprise.inject.spi.BeanManager;

import javax.interceptor.InterceptorBinding;

import org.apache.deltaspike.core.util.ClassUtils;
import org.apache.deltaspike.core.util.ServiceUtils;
import org.apache.deltaspike.proxy.spi.ProxyClassGenerator;

public abstract class DeltaSpikeProxyFactory
{
    private static final String SUPER_ACCESSOR_METHOD_SUFFIX = "$super";
    
    public static class GeneratorHolder
    {
        private static ProxyClassGenerator generator;

        /**
         * Setter invoked by OSGi Service Component Runtime.
         *
         * @param generator
         *            generator service
         */
        public void setGenerator(ProxyClassGenerator generator)
        {
            GeneratorHolder.generator = generator;
        }
    }


    /**
     * Looks up a unique service implementation.
     *
     * @return ProxyClassGenerator service
     */
    private static ProxyClassGenerator lookupService()
    {
        if (GeneratorHolder.generator == null)
        {
            List proxyClassGeneratorList = ServiceUtils
                .loadServiceImplementations(ProxyClassGenerator.class);

            if (proxyClassGeneratorList.size() != 1)
            {
                throw new IllegalStateException(proxyClassGeneratorList.size()
                    + " implementations of " + ProxyClassGenerator.class.getName()
                    + " found. Expected exactly one implementation.");
            }
            GeneratorHolder.generator = proxyClassGeneratorList.get(0);
        }
        return GeneratorHolder.generator;
    }

    public  Class resolveAlreadyDefinedProxyClass(Class targetClass)
    {
        Class proxyClass = ClassUtils.tryToLoadClassForName(constructProxyClassName(targetClass),
                targetClass,
                targetClass.getClassLoader());

        return proxyClass;
    }
    
    public  Class getProxyClass(BeanManager beanManager, Class targetClass)
    {
        // check if a proxy is already defined for this class
        Class proxyClass = resolveAlreadyDefinedProxyClass(targetClass);
        if (proxyClass == null)
        {
            proxyClass = createProxyClass(beanManager, targetClass.getClassLoader(), targetClass);
        }

        return proxyClass;
    }

    private synchronized  Class createProxyClass(BeanManager beanManager, ClassLoader classLoader,
            Class targetClass)
    {
        Class proxyClass = resolveAlreadyDefinedProxyClass(targetClass);
        if (proxyClass == null)
        {
            ArrayList allMethods = collectAllMethods(targetClass);
            ArrayList interceptMethods = filterInterceptMethods(targetClass, allMethods);
            ArrayList delegateMethods = getDelegateMethods(targetClass, allMethods);

            // check if a interceptor is defined on class level. if not, skip interceptor methods
            if (interceptMethods != null
                    && interceptMethods.size() > 0
                    && !containsInterceptorBinding(beanManager, targetClass.getDeclaredAnnotations()))
            {
                // loop every method and check if a interceptor is defined on the method -> otherwise don't overwrite
                // interceptMethods
                Iterator iterator = interceptMethods.iterator();
                while (iterator.hasNext())
                {
                    Method method = iterator.next();
                    if (!containsInterceptorBinding(beanManager, method.getDeclaredAnnotations()))
                    {
                        iterator.remove();
                    }
                }
            }

            ProxyClassGenerator proxyClassGenerator = lookupService();

            proxyClass = proxyClassGenerator.generateProxyClass(classLoader,
                    targetClass,
                    getProxyClassSuffix(),
                    SUPER_ACCESSOR_METHOD_SUFFIX,
                    getAdditionalInterfacesToImplement(targetClass),
                    delegateMethods == null ? new Method[0]
                            : delegateMethods.toArray(new Method[delegateMethods.size()]),
                    interceptMethods == null ? new Method[0]
                            : interceptMethods.toArray(new Method[interceptMethods.size()]));
        }

        return proxyClass;
    }

    protected boolean containsInterceptorBinding(BeanManager beanManager, Annotation[] annotations)
    {
        for (Annotation annotation : annotations)
        {            
            Class annotationType = annotation.annotationType();
            
            if (annotationType.isAnnotationPresent(InterceptorBinding.class))
            {
                return true;
            }

            if (beanManager.isStereotype(annotationType))
            {                
                boolean containsInterceptorBinding = containsInterceptorBinding(
                        beanManager,
                        annotationType.getDeclaredAnnotations());
                
                if (containsInterceptorBinding)
                {
                    return true;
                }
            }
        }
        
        return false;
    }
        
    protected String constructProxyClassName(Class clazz)
    {
        return clazz.getName() + getProxyClassSuffix();
    }

    protected static String constructSuperAccessorMethodName(Method method)
    {
        return method.getName() + SUPER_ACCESSOR_METHOD_SUFFIX;
    }
    
    public static Method getSuperAccessorMethod(Object proxy, Method method) throws NoSuchMethodException
    {
        return proxy.getClass().getMethod(
                constructSuperAccessorMethodName(method),
                method.getParameterTypes());
    }
    
    /**
     * Checks if the given class is DS proxy class.
     *
     * @param clazz
     * @return
     */
    public boolean isProxyClass(Class clazz)
    {
        return clazz.getName().endsWith(getProxyClassSuffix());
    }

    protected boolean hasSameSignature(Method a, Method b)
    {
        return a.getName().equals(b.getName())
                && a.getReturnType().equals(b.getReturnType())
                && Arrays.equals(a.getParameterTypes(), b.getParameterTypes());
    }

    protected boolean ignoreMethod(Method method, List methods)
    {
        // we have no interest in generics bridge methods
        if (method.isBridge())
        {
            return true;
        }

        // we do not proxy finalize()
        if ("finalize".equals(method.getName()))
        {
            return true;
        }

        // same method...
        if (methods.contains(method))
        {
            return true;
        }

        // check if a method with the same signature is already available
        for (Method currentMethod : methods)
        {
            if (hasSameSignature(currentMethod, method))
            {
                return true;
            }
        }

        return false;
    }
    
    protected ArrayList collectAllMethods(Class clazz)
    {
        ArrayList methods = new ArrayList();
        for (Method method : clazz.getDeclaredMethods())
        {
            if (!ignoreMethod(method, methods))
            {
                methods.add(method);
            }
        }
        for (Method method : clazz.getMethods())
        {
            if (!ignoreMethod(method, methods))
            {
                methods.add(method);
            }
        }

        // collect methods from abstract super classes...
        Class currentSuperClass = clazz.getSuperclass();
        while (currentSuperClass != null)
        {
            if (Modifier.isAbstract(currentSuperClass.getModifiers()))
            {
                for (Method method : currentSuperClass.getDeclaredMethods())
                {
                    if (!ignoreMethod(method, methods))
                    {
                        methods.add(method);
                    }
                }
                for (Method method : currentSuperClass.getMethods())
                {
                    if (!ignoreMethod(method, methods))
                    {
                        methods.add(method);
                    }
                }
            }
            currentSuperClass = currentSuperClass.getSuperclass();
        }

        // sort out somewhere implemented abstract methods
        Class currentClass = clazz;
        while (currentClass != null)
        {
            Iterator methodIterator = methods.iterator();
            while (methodIterator.hasNext())
            {
                Method method = methodIterator.next();
                if (Modifier.isAbstract(method.getModifiers()))
                {
                    try
                    {
                        Method foundMethod = currentClass.getMethod(method.getName(), method.getParameterTypes());
                        // if method is implementent in the current class -> remove it
                        if (foundMethod != null && !Modifier.isAbstract(foundMethod.getModifiers()))
                        {
                            methodIterator.remove();
                        }
                    }
                    catch (Exception e)
                    {
                        // ignore...
                    }
                }
            }

            currentClass = currentClass.getSuperclass();
        }

        return methods;
    }
    
    protected ArrayList filterInterceptMethods(Class targetClass, ArrayList allMethods)
    {
        ArrayList methods = new ArrayList();
        
        Iterator it = allMethods.iterator();
        while (it.hasNext())
        {
            Method method = it.next();

            if (Modifier.isPublic(method.getModifiers())
                    && !Modifier.isFinal(method.getModifiers())
                    && !Modifier.isAbstract(method.getModifiers()))
            {
                methods.add(method);
            }
        }
        
        return methods;
    }
    
    protected Class[] getAdditionalInterfacesToImplement(Class targetClass)
    {
        return null;
    }
    
    protected abstract ArrayList getDelegateMethods(Class targetClass, ArrayList allMethods);
    
    protected abstract String getProxyClassSuffix();
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy