KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sape > carbon > core > component > proxy > DefaultComponentProxyInvocationHandler


1 /*
2  * The contents of this file are subject to the Sapient Public License
3  * Version 1.0 (the "License"); you may not use this file except in compliance
4  * with the License. You may obtain a copy of the License at
5  * http://carbon.sf.net/License.html.
6  *
7  * Software distributed under the License is distributed on an "AS IS" basis,
8  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
9  * the specific language governing rights and limitations under the License.
10  *
11  * The Original Code is The Carbon Component Framework.
12  *
13  * The Initial Developer of the Original Code is Sapient Corporation
14  *
15  * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
16  */

17
18 package org.sape.carbon.core.component.proxy;
19
20 import java.lang.reflect.InvocationTargetException JavaDoc;
21 import java.lang.reflect.Method JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.Arrays JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.Map JavaDoc;
27
28 import org.sape.carbon.core.component.Component;
29 import org.sape.carbon.core.component.FunctionalInterface;
30 import org.sape.carbon.core.util.reflection.ClassUtil;
31 import org.sape.carbon.core.util.reflection.GenericProxy;
32 import org.sape.carbon.core.util.thread.ReadWriteLock;
33 import org.sape.carbon.core.util.thread.ReentrantWriterPreferenceReadWriteLock;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38
39 /**
40  * Provides the glue for the Component, and supporting container functionality.
41  * <code>DefaultComponentProxyInvocationHandler</code> is a Dynamic Proxy
42  * Invocation Handler. Its job is to masquerade as either the Component, or
43  * any one of a number of container-feature-providers. called 'Assistants'.
44  * Mappings from interfaces to delegates (being the component instance, or
45  * interceptor instances) are stored. Invocations on those interfaces are passed
46  * to the corresponding delegates. In addition, Assistants may listen for
47  * <code>ProxyEvent</code>s - which are distributed immediately before and after
48  * an invocation being passed to a delegate. Listeners are notified in the order
49  * they are registered, according to the <code>ComponentTemplateConfiguration
50  * </code>.
51  *
52  * Copyright 2002 Sapient
53  * @see java.lang.reflect.Proxy
54  * @see org.sape.carbon.core.component.proxy.Decorator
55  * @see org.sape.carbon.core.component.proxy.Interceptor
56  * @see org.sape.carbon.core.component.factory.ComponentTemplateConfiguration
57  * @since carbon 1.0
58  * @author Chris Herron, February 2002
59  * @version $Revision: 1.44 $($Author: dvoet $ / $Date: 2003/05/05 21:21:14 $)
60  */

61 public class DefaultComponentProxyInvocationHandler
62     extends GenericProxy
63     implements ComponentProxyInvocationHandler {
64
65
66     /**
67      * Map of interfaces to their respective delegates. Upon calls to this
68      * component, the target object that will have the supplied method
69      * executed will come from this map.
70      */

71     protected Map JavaDoc delegatesByInterface = new HashMap JavaDoc();
72
73     /**
74      * This list is a list of interceptors that will be called in the
75      * execution of the represented component. These interceptors call
76      * eachother, in order of this list. The head interceptor is executed
77      * by this handler.
78      */

79     protected List JavaDoc interceptors = new ArrayList JavaDoc();
80
81     /**
82      * A reference to the first interceptor in the chain. This interceptor
83      * is always called first.
84      */

85     protected Interceptor headInterceptor;
86
87     /** Method that gets the component name if such method exists. */
88     private static Method JavaDoc GET_COMPONENT_NAME_METHOD;
89
90     /** Provides a handle to Apache-commons logger. */
91     private Log log =
92         LogFactory.getLog(this.getClass());
93
94
95
96     static {
97         try {
98             GET_COMPONENT_NAME_METHOD =
99                     Component.class.getMethod(
100                             "getComponentName",
101                             new Class JavaDoc[] {});
102         } catch (NoSuchMethodException JavaDoc nsme) {
103             // Do nothing
104
}
105     }
106
107     /**
108      * The monitor object that coordinates read/write calls to
109      * the represented component. Read calls are considered to
110      * be calls to the component's Functional Interface and should
111      * not change the fundamental lifecylcle of the component.
112      * Write calls are considered calls to the Component Assistant
113      * Delegates that may have effect on the configuration or
114      * lifecycle of the component. Multiple readers are allowed at
115      * one time, but only a single writer (with no readers active)
116      * is allowed.
117      */

118     private final ReadWriteLock monitor =
119         new ReentrantWriterPreferenceReadWriteLock();
120
121     /**
122      * The implementation of the true component.
123      */

124     protected FunctionalInterface functionalImplementation;
125
126     /** The name of wrapped component. */
127     protected String JavaDoc componentName = null;
128
129     /**
130      * Method used during creation of the proxy object to add Assistants
131      * to the component. This mehtod should be called only from the
132      * ComponentFactory when it is creating a new component.
133      *
134      * @see ComponentFactory
135      * @since carbon 2.0
136      */

137     public void addDecorator(Decorator decorator) {
138         addDelegate(
139             ClassUtil.getSuperInterfaces(decorator.getExposedInterfaces()),
140             decorator);
141     }
142
143     /**
144      * Method used during creation of the proxy object to add the
145      * functional implementation
146      * to the component. This mehtod should be called only from the
147      * ComponentFactory when it is creating a new component.
148      *
149      * @see ComponentFactory
150      *
151      * @param implementedInterfaces all the interfaces (including
152      * super interfaces) implemented by functionalImplementation's
153      * FunctionalInterface
154      * @param functionalImplementation the object that implements the
155      * components FunctionalInterface
156      */

157     public void setFunctionalImplementation(
158             Class JavaDoc[] implementedInterfaces,
159             FunctionalInterface functionalImplementation) {
160
161         addDelegate(
162             implementedInterfaces,
163             functionalImplementation);
164
165         this.functionalImplementation = functionalImplementation;
166
167     }
168
169
170     /**
171      * Add a delegate.
172      *
173      * @param representedInterfaces an array of interfaces for which this
174      * delegate may be invoked
175      * @param delegate an instance of the delegate to be delegated to
176      */

177     protected void addDelegate(
178         Class JavaDoc[] representedInterfaces,
179         Object JavaDoc delegate) {
180
181         if (log.isTraceEnabled()) {
182             log.trace("Adding delegate ["
183                     + delegate.getClass().getName()
184                     + "] for interfaces "
185                     + Arrays.asList(representedInterfaces));
186         }
187
188
189
190
191         for (int i = 0; i < representedInterfaces.length; i++) {
192             Class JavaDoc currentInterface = representedInterfaces[i];
193
194             //add the interface->delegate mapping
195
Object JavaDoc previousDelegate =
196                 this.delegatesByInterface.put(
197                     currentInterface,
198                     delegate);
199
200             // check to make sure another delegate is not linked to this
201
// interface
202
if (previousDelegate != null) {
203
204                 if (log.isWarnEnabled()) {
205                     log.warn(
206                         "Multiple delegates represent the same interface. "
207                         + "Conflicting delegates: ["
208                         + previousDelegate.getClass().getName()
209                         + ","
210                         + delegate.getClass().getName()
211                         + "], using the latter");
212                 }
213             }
214         }
215
216         // Setup interceptor support if the delegate is an interceptor
217
if (delegate instanceof Interceptor) {
218             if (log.isTraceEnabled()) {
219             log.trace(
220                 "Recognized interceptor ["
221                 + delegate.getClass().getName()
222                 + "], adding to chain.");
223             }
224             addInterceptor((Interceptor) delegate);
225         }
226     }
227
228     /**
229      * Adds an interceptor the chain.
230      *
231      * @param interceptor the interceptor to add
232      */

233     private void addInterceptor(Interceptor interceptor) {
234
235         if (log.isTraceEnabled()) {
236             log.trace(
237                 "Adding Interceptor to chain ["
238                 + interceptor.getClass().getName()
239                 + "]");
240         }
241         if (!this.interceptors.isEmpty()) {
242             Interceptor previousInterceptor =
243                 (Interceptor)
244                 this.interceptors.get(this.interceptors.size() - 1);
245
246             previousInterceptor.setNextInterceptor(interceptor);
247         }
248
249         this.interceptors.add(interceptor);
250
251         if (this.headInterceptor == null) {
252             this.headInterceptor = interceptor;
253         }
254
255     }
256
257     /**
258      * Gets the delegate based on the given interface.
259      *
260      * @param delegateInterface the interface to get the delegate for
261      * @return the delegate for the given interface
262      */

263     public Object JavaDoc getDelegate(Class JavaDoc delegateInterface) {
264         return this.delegatesByInterface.get(delegateInterface);
265     }
266
267     /**
268      * Gets the read-lock monitor.
269      *
270      * @return the read-lock monitor
271      */

272     public ReadWriteLock getMonitor() {
273         return this.monitor;
274     }
275
276     /**
277      * Gets the component name.
278      *
279      * @return the component name
280      */

281     public String JavaDoc getComponentName() {
282         return this.componentName;
283     }
284
285     /**
286      * Sets the name of the component.
287      *
288      * @param componentName the name of the component
289      */

290     public void setComponentName(String JavaDoc componentName) {
291         this.componentName = componentName;
292     }
293
294     /**
295      * This method implements the delegation model for the represented
296      * component. It will pass component calls to the implementation object
297      * for a component as well as passing other calls to configured
298      * Component Assistant instances.
299      *
300      * @param proxy the object that is being represented
301      * @param method the method descriptor for the method called
302      * @param args an array of arguments passed to that method
303      * @throws Throwable when there is an exception thrown from the
304      * delegated method. This may be a Checked
305      * exception if the implemented interface declares
306      * the exception. Otherwise checked exceptions will
307      * be automatically wrapped in an
308      * <code>UndeclaredThrowableException</code>.
309      * Runtime exceptions are thrown as is.
310      * @return the return value of the delegated method.
311      */

312     protected Object JavaDoc handleInvoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args)
313         throws Throwable JavaDoc {
314
315         // special handling for getComponentName
316
if (GET_COMPONENT_NAME_METHOD.equals(method)) {
317             return getComponentName();
318         }
319
320         Class JavaDoc subjectInterface = method.getDeclaringClass();
321
322         Object JavaDoc target = getDelegate(subjectInterface);
323         if (target == null) {
324             // Should never happen
325
}
326
327         Invocation invocation =
328             new Invocation(
329                     target,
330                     method,
331                     args,
332                     method.getParameterTypes(),
333                     target == this.functionalImplementation);
334
335         Object JavaDoc result = null;
336
337         boolean lockAquired = false;
338         if (target == this.functionalImplementation) {
339             this.monitor.readLock().acquire();
340             lockAquired = true;
341         }
342
343         try {
344
345             result = this.headInterceptor.invoke(invocation);
346
347         } catch (InvocationTargetException JavaDoc ite) {
348             // unwrap the exception
349
throw ite.getTargetException();
350
351         } finally {
352             if (lockAquired) {
353                 this.monitor.readLock().release();
354             }
355         }
356
357         return result;
358     }
359
360     /**
361      * Returns out the name of the component
362      *
363      * @param proxy the proxy object to toString
364      * @return the String representation of the proxy object
365      */

366     protected String JavaDoc proxyToString(Object JavaDoc proxy) {
367         return getComponentName();
368     }
369
370 }
371
Popular Tags