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 *****************************************************************************/
009package org.picocontainer.behaviors;
010
011import org.picocontainer.ComponentAdapter;
012import org.picocontainer.PicoContainer;
013
014import java.util.Map;
015import java.util.HashMap;
016import java.lang.reflect.Method;
017import java.lang.reflect.InvocationTargetException;
018import java.io.Serializable;
019
020/** @author Paul Hammant */
021@SuppressWarnings("serial")
022public 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}