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     *****************************************************************************/
009    package org.picocontainer.behaviors;
010    
011    import org.picocontainer.ComponentAdapter;
012    import org.picocontainer.PicoContainer;
013    
014    import java.util.Map;
015    import java.util.HashMap;
016    import java.lang.reflect.Method;
017    import java.lang.reflect.InvocationTargetException;
018    import java.io.Serializable;
019    
020    /** @author Paul Hammant */
021    public class Intercepted<T> extends HiddenImplementation {
022    
023        private final Map<Class, Object> pres = new HashMap<Class, Object>();
024        private final Map<Class, Object> posts = new HashMap<Class, Object>();
025        private Controller controller = new ControllerWrapper(new InterceptorThreadLocal());
026    
027        public Intercepted(ComponentAdapter delegate) {
028            super(delegate);
029        }
030    
031        public void addPreInvocation(Class type, Object interceptor) {
032            pres.put(type, interceptor);
033        }
034    
035        public void addPostInvocation(Class type, Object interceptor) {
036            posts.put(type, interceptor);
037        }
038    
039        protected Object invokeMethod(Method method, Object[] args, PicoContainer container) throws Throwable {
040            Object componentInstance = getDelegate().getComponentInstance(container);
041            try {
042                controller.clear();
043                controller.instance(componentInstance);
044                Object pre = pres.get(method.getDeclaringClass());
045                if (pre != null) {
046                    Object rv =  method.invoke(pre, args);
047                    if (controller.isVetoed()) {
048                        return rv;
049                    }
050                }
051                Object result = method.invoke(componentInstance, args);
052                controller.setOriginalRetVal(result);
053                Object post = posts.get(method.getDeclaringClass());
054                if (post != null) {
055                    Object rv = method.invoke(post, args);
056                    if (controller.isOverridden()) {
057                        return rv;
058                    }
059                }
060                return result;
061            } catch (final InvocationTargetException ite) {
062                throw ite.getTargetException();
063            }
064        }
065    
066        public Controller getController() {
067            return controller;
068        }
069    
070        public static class InterceptorThreadLocal extends ThreadLocal implements Serializable {
071            protected Object initialValue() {
072                return new ControllerImpl();
073            }
074        }
075    
076        public interface Controller {
077            void veto();
078    
079            void clear();
080    
081            boolean isVetoed();
082    
083            void setOriginalRetVal(Object retVal);
084    
085            boolean isOverridden();
086    
087            void instance(Object instance);
088    
089            Object getOriginalRetVal();
090    
091            void override();
092        }
093    
094        public static class ControllerImpl implements Controller {
095            private boolean vetoed;
096            private Object retVal;
097            private boolean overridden;
098            private Object instance;
099    
100            public void veto() {
101                vetoed = true;
102            }
103    
104            public void clear() {
105                vetoed = false;
106                overridden = false;
107                retVal = null;
108                instance = null;
109            }
110    
111            public boolean isVetoed() {
112                return vetoed;
113            }
114            public void setOriginalRetVal(Object retVal) {
115                this.retVal = retVal;
116            }
117    
118            public Object getOriginalRetVal() {
119                return retVal;
120            }
121    
122            public boolean isOverridden() {
123                return overridden;
124            }
125    
126            public void instance(Object instance) {
127                this.instance = instance;
128            }
129    
130            public void override() {
131                overridden = true;
132            }
133        }
134    
135        public class ControllerWrapper implements Controller {
136            private final ThreadLocal threadLocal;
137    
138            public ControllerWrapper(ThreadLocal threadLocal) {
139                this.threadLocal = threadLocal;
140            }
141    
142            public void veto() {
143                ((Controller) threadLocal.get()).veto();
144            }
145    
146            public void clear() {
147                ((Controller) threadLocal.get()).clear();
148            }
149    
150            public boolean isVetoed() {
151                return ((Controller) threadLocal.get()).isVetoed();
152            }
153    
154            public void setOriginalRetVal(Object retVal) {
155                ((Controller) threadLocal.get()).setOriginalRetVal(retVal);
156            }
157    
158            public Object getOriginalRetVal() {
159                return ((Controller) threadLocal.get()).getOriginalRetVal();
160            }
161    
162            public boolean isOverridden() {
163                return ((Controller) threadLocal.get()).isOverridden();
164            }
165    
166            public void instance(Object instance) {
167                ((Controller) threadLocal.get()).instance(instance);
168    
169            }
170    
171            public void override() {
172                ((Controller) threadLocal.get()).override();
173            }
174        }
175    
176    
177    
178        protected String getName() {
179            return "Intercepted:";
180        }
181    }