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