001    /*****************************************************************************
002     * Copyright (c) PicoContainer Organization. All rights reserved.            *
003     * ------------------------------------------------------------------------- *
004     * The software in this package is published under the terms of the BSD      *
005     * style license a copy of which has been included with this distribution in *
006     * the LICENSE.txt file.                                                     *
007     *                                                                           *
008     * Idea by Rachel Davies, Original code by various                           *
009     *****************************************************************************/
010    package org.nanocontainer.aop.dynaop;
011    
012    import dynaop.Aspects;
013    import dynaop.Interceptor;
014    import dynaop.InterceptorFactory;
015    import dynaop.ProxyFactory;
016    import dynaop.util.Classes;
017    import org.aopalliance.intercept.MethodInterceptor;
018    import org.nanocontainer.aop.AspectsManager;
019    import org.nanocontainer.aop.ClassPointcut;
020    import org.nanocontainer.aop.ComponentPointcut;
021    import org.nanocontainer.aop.MethodPointcut;
022    import org.nanocontainer.aop.PointcutsFactory;
023    import org.picocontainer.PicoContainer;
024    
025    import java.lang.reflect.Method;
026    
027    /**
028     * An <code>AspectsManager</code> implemented using dynaop.
029     *
030     * @author Stephen Molitor
031     * @version $Revision: 3144 $
032     */
033    public class DynaopAspectsManager implements AspectsManager {
034    
035        private final Aspects containerAspects;
036        private final PointcutsFactory pointcutsFactory;
037        private final ContainerLoader containerLoader = new ContainerLoader();
038        private final PicoContainer container = PicoContainerProxy.create(containerLoader);
039        private final ComponentAspectsCollection componentAspects = new ComponentAspectsCollection();
040    
041        /**
042         * Creates a new <code>DynaopAspectsManager</code> that will used the
043         * given <code>dynaop.Aspects</code> object and pointcuts factory. This
044         * constructor might be useful if the <code>containerAspects</code> object
045         * contains aspects already configured via dynaop's API, perhaps using
046         * dynaop's BeanShell configuration mechanism.
047         *
048         * @param containerAspects the <code>dyanop.Aspects</code> object used to
049         *                         contain the aspects.
050         * @param pointcutsFactory the pointcuts factory.
051         */
052        public DynaopAspectsManager(Aspects containerAspects, PointcutsFactory pointcutsFactory) {
053            this.containerAspects = containerAspects;
054            this.pointcutsFactory = pointcutsFactory;
055        }
056    
057        /**
058         * Creates a new <code>DynaopAspectsManager</code> that will used the
059         * given <code>dynaop.Aspects</code> object. This constructor might be
060         * useful if the <code>containerAspects</code> object contains aspects
061         * already configured via dynaop's API, perhaps using dynaop's BeanShell
062         * configuration mechanism.
063         *
064         * @param containerAspects the <code>dyanop.Aspects</code> object used to
065         *                         contain the aspects.
066         */
067        public DynaopAspectsManager(Aspects containerAspects) {
068            this(containerAspects, new DynaopPointcutsFactory());
069        }
070    
071        /**
072         * Creates a new <code>DynaopAspectsManager</code> that will use the given
073         * pointcuts factory.
074         *
075         * @param pointcutsFactory the pointcuts factory.
076         */
077        public DynaopAspectsManager(PointcutsFactory pointcutsFactory) {
078            this(new Aspects(), pointcutsFactory);
079        }
080    
081        /**
082         * Creates a new <code>DynaopAspectsManager</code>.
083         */
084        public DynaopAspectsManager() {
085            this(new Aspects());
086        }
087    
088        public void registerInterceptor(ClassPointcut classPointcut, MethodPointcut methodPointcut,
089                                        Object interceptorComponentKey) {
090            containerAspects.interceptor(getClassPointcut(classPointcut), getMethodPointcut(methodPointcut),
091                    createInterceptorFactory(interceptorComponentKey));
092        }
093    
094        public void registerInterceptor(ClassPointcut classPointcut, MethodPointcut methodPointcut,
095                                        MethodInterceptor interceptor) {
096            containerAspects.interceptor(getClassPointcut(classPointcut), getMethodPointcut(methodPointcut),
097                    createInterceptor(interceptor));
098        }
099    
100        public void registerInterceptor(ComponentPointcut componentPointcut, MethodPointcut methodPointcut,
101                                        Object interceptorComponentKey) {
102            componentAspects.add(new InterceptorComponentAspect(componentPointcut, getMethodPointcut(methodPointcut),
103                    createInterceptorFactory(interceptorComponentKey)));
104        }
105    
106        public void registerInterceptor(ComponentPointcut componentPointcut, MethodPointcut methodPointcut,
107                                        MethodInterceptor interceptor) {
108            componentAspects.add(new InterceptorComponentAspect(componentPointcut, getMethodPointcut(methodPointcut),
109                    createInterceptor(interceptor)));
110        }
111    
112        public void registerMixin(ClassPointcut classPointcut, Class mixinClass) {
113            registerMixin(classPointcut, Classes.getAllInterfaces(mixinClass), mixinClass);
114        }
115    
116        public void registerMixin(ClassPointcut classPointcut, Class[] interfaces, Class mixinClass) {
117            containerAspects.mixin(getClassPointcut(classPointcut), interfaces, new ContainerSuppliedMixinFactory(container, mixinClass));
118        }
119    
120        public void registerMixin(ComponentPointcut componentPointcut, Class mixinClass) {
121            registerMixin(componentPointcut, Classes.getAllInterfaces(mixinClass), mixinClass);
122        }
123    
124        public void registerMixin(ComponentPointcut componentPointcut, Class[] interfaces, Class mixinClass) {
125            componentAspects.add(new MixinComponentAspect(componentPointcut, interfaces, new ContainerSuppliedMixinFactory(container, mixinClass)));
126        }
127    
128        public void registerInterfaces(ClassPointcut classPointcut, Class[] interfaces) {
129            containerAspects.interfaces(getClassPointcut(classPointcut), interfaces);
130        }
131    
132        public void registerInterfaces(ComponentPointcut componentPointcut, Class[] interfaces) {
133            componentAspects.add(new InterfacesComponentAspect(componentPointcut, interfaces));
134        }
135    
136        public PointcutsFactory getPointcutsFactory() {
137            return pointcutsFactory;
138        }
139    
140        public Object applyAspects(Object componentKey, Object component, PicoContainer container) {
141            containerLoader.setContainer(container);
142            Aspects aspects = componentAspects.registerAspects(componentKey, containerAspects);
143            return ProxyFactory.getInstance(aspects).wrap(component);
144        }
145    
146        private dynaop.ClassPointcut getClassPointcut(final ClassPointcut classPointcut) {
147            if (classPointcut instanceof dynaop.ClassPointcut) {
148                return (dynaop.ClassPointcut) classPointcut;
149            }
150            return new dynaop.ClassPointcut() {
151                public boolean picks(Class clazz) {
152                    return classPointcut.picks(clazz);
153                }
154            };
155        }
156    
157        private dynaop.MethodPointcut getMethodPointcut(final MethodPointcut methodPointcut) {
158            if (methodPointcut instanceof dynaop.MethodPointcut) {
159                return (dynaop.MethodPointcut) methodPointcut;
160            }
161            return new dynaop.MethodPointcut() {
162                public boolean picks(Method method) {
163                    return methodPointcut.picks(method);
164                }
165            };
166        }
167    
168        private Interceptor createInterceptor(MethodInterceptor methodInterceptor) {
169            return new MethodInterceptorAdapter(methodInterceptor);
170        }
171    
172        private InterceptorFactory createInterceptorFactory(Object interceptorComponent) {
173            return new ContainerSuppliedInterceptorFactory(container, interceptorComponent);
174        }
175    
176    }