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 getOriginalRetVal();
093    
094            void override();
095        }
096    
097        public static class ControllerImpl implements Controller {
098            private boolean vetoed;
099            private Object retVal;
100            private boolean overridden;
101            private Object instance;
102    
103            public void veto() {
104                vetoed = true;
105            }
106    
107            public void clear() {
108                vetoed = false;
109                overridden = false;
110                retVal = null;
111                instance = null;
112            }
113    
114            public boolean isVetoed() {
115                return vetoed;
116            }
117            public void setOriginalRetVal(Object retVal) {
118                this.retVal = retVal;
119            }
120    
121            public Object getOriginalRetVal() {
122                return retVal;
123            }
124    
125            public boolean isOverridden() {
126                return overridden;
127            }
128    
129            public void instance(Object instance) {
130                this.instance = instance;
131            }
132    
133            public void override() {
134                overridden = true;
135            }
136        }
137    
138        public class ControllerWrapper implements Controller {
139            private final ThreadLocal threadLocal;
140    
141            public ControllerWrapper(ThreadLocal threadLocal) {
142                this.threadLocal = threadLocal;
143            }
144    
145            public void veto() {
146                ((Controller) threadLocal.get()).veto();
147            }
148    
149            public void clear() {
150                ((Controller) threadLocal.get()).clear();
151            }
152    
153            public boolean isVetoed() {
154                return ((Controller) threadLocal.get()).isVetoed();
155            }
156    
157            public void setOriginalRetVal(Object retVal) {
158                ((Controller) threadLocal.get()).setOriginalRetVal(retVal);
159            }
160    
161            public Object getOriginalRetVal() {
162                return ((Controller) threadLocal.get()).getOriginalRetVal();
163            }
164    
165            public boolean isOverridden() {
166                return ((Controller) threadLocal.get()).isOverridden();
167            }
168    
169            public void instance(Object instance) {
170                ((Controller) threadLocal.get()).instance(instance);
171    
172            }
173    
174            public void override() {
175                ((Controller) threadLocal.get()).override();
176            }
177        }
178    
179        public String getDescriptor() {
180            return "Intercepted";
181        }
182    }