KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > aop > support > DelegatePerTargetObjectIntroductionInterceptor


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.aop.support;
18
19 import java.util.Map JavaDoc;
20 import java.util.WeakHashMap JavaDoc;
21
22 import org.aopalliance.intercept.MethodInvocation;
23
24 import org.springframework.aop.DynamicIntroductionAdvice;
25 import org.springframework.aop.IntroductionInterceptor;
26 import org.springframework.aop.ProxyMethodInvocation;
27
28 /**
29  * Convenient implementation of the
30  * {@link org.springframework.aop.IntroductionInterceptor} interface.
31  *
32  * <p>This differs from {@link DelegatingIntroductionInterceptor} in that a single
33  * instance of this class can be used to advise multiple target objects, and each target
34  * object will have its <i>own</i> delegate (whereas DelegatingIntroductionInterceptor
35  * shares the same delegate, and hence the same state across all targets).
36  *
37  * <p>The <code>suppressInterface</code> method can be used to suppress interfaces
38  * implemented by the delegate class but which should not be introduced to the
39  * owning AOP proxy.
40  *
41  * <p>An instance of this class is serializable if the delegates are.
42  *
43  * <p><i>Note: There are some implementation similarities between this class and
44  * {@link DelegatingIntroductionInterceptor} that suggest a possible refactoring
45  * to extract a common ancestor class in the future.</i>
46  *
47  * @author Adrian Colyer
48  * @author Juergen Hoeller
49  * @since 2.0
50  * @see #suppressInterface
51  * @see DelegatingIntroductionInterceptor
52  */

53 public class DelegatePerTargetObjectIntroductionInterceptor extends IntroductionInfoSupport
54         implements IntroductionInterceptor {
55
56     /**
57      * Hold weak references to keys as we don't want to interfere with garbage collection..
58      */

59     private Map JavaDoc delegateMap = new WeakHashMap JavaDoc();
60
61     private Class JavaDoc defaultImplType;
62
63     private Class JavaDoc interfaceType;
64
65
66     public DelegatePerTargetObjectIntroductionInterceptor(Class JavaDoc defaultImplType, Class JavaDoc interfaceType) {
67         this.defaultImplType = defaultImplType;
68         this.interfaceType = interfaceType;
69         // cCeate a new delegate now (but don't store it in the map).
70
// We do this for two reasons:
71
// 1) to fail early if there is a problem instantiating delegates
72
// 2) to populate the interface map once and once only
73
Object JavaDoc delegate = createNewDelegate();
74         implementInterfacesOnObject(delegate);
75         suppressInterface(IntroductionInterceptor.class);
76         suppressInterface(DynamicIntroductionAdvice.class);
77     }
78
79
80     /**
81      * Subclasses may need to override this if they want to perform custom
82      * behaviour in around advice. However, subclasses should invoke this
83      * method, which handles introduced interfaces and forwarding to the target.
84      */

85     public Object JavaDoc invoke(MethodInvocation mi) throws Throwable JavaDoc {
86         if (isMethodOnIntroducedInterface(mi)) {
87             Object JavaDoc delegate = getIntroductionDelegateFor(mi.getThis());
88             
89             // Using the following method rather than direct reflection,
90
// we get correct handling of InvocationTargetException
91
// if the introduced method throws an exception.
92
Object JavaDoc retVal = AopUtils.invokeJoinpointUsingReflection(delegate, mi.getMethod(), mi.getArguments());
93             
94             // Massage return value if possible: if the delegate returned itself,
95
// we really want to return the proxy.
96
if (retVal == delegate && mi instanceof ProxyMethodInvocation) {
97                 retVal = ((ProxyMethodInvocation) mi).getProxy();
98             }
99             return retVal;
100         }
101
102         return doProceed(mi);
103     }
104
105     /**
106      * Proceed with the supplied {@link org.aopalliance.intercept.MethodInterceptor}.
107      * Subclasses can override this method to intercept method invocations on the
108      * target object which is useful when an introduction needs to monitor the object
109      * that it is introduced into. This method is <strong>never</strong> called for
110      * {@link MethodInvocation MethodInvocations} on the introduced interfaces.
111      */

112     protected Object JavaDoc doProceed(MethodInvocation mi) throws Throwable JavaDoc {
113         // If we get here, just pass the invocation on.
114
return mi.proceed();
115     }
116
117     private Object JavaDoc getIntroductionDelegateFor(Object JavaDoc targetObject) {
118         synchronized(this.delegateMap) {
119             if (this.delegateMap.containsKey(targetObject)) {
120                 return this.delegateMap.get(targetObject);
121             }
122             else {
123                 Object JavaDoc delegate = createNewDelegate();
124                 this.delegateMap.put(targetObject, delegate);
125                 return delegate;
126             }
127         }
128     }
129     
130     private Object JavaDoc createNewDelegate() {
131         try {
132             return this.defaultImplType.newInstance();
133         }
134         catch (Throwable JavaDoc ex) {
135             throw new IllegalArgumentException JavaDoc("Cannot create default implementation for '" +
136                     this.interfaceType.getName() + "' mixin (" + this.defaultImplType.getName() + "): " + ex);
137         }
138     }
139
140 }
141
Popular Tags