1 /*
2 * JoinPoint.java
3 * Created on August 30, 2003
4 *
5 * The Blues Framework - A lightweight application framework
6 * Copyright (C) 2003 Lonnie Pryor
7 * http://blues.lonniepryor.com
8 *
9 * This library is free software; you can redistribute it and/or modify it under the
10 * terms of the GNU Lesser General Public License as published by the Free Software
11 * Foundation; either version 2.1 of the License, or (at your option) any later
12 * version.
13 *
14 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
16 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License along
19 * with this library; if not, write to:
20 *
21 * The Free Software Foundation, Inc.
22 * 59 Temple Place, Suite 330
23 * Boston, MA 02111-1307 USA
24 *
25 */
26 package com.lonniepryor.blues.sys;
27
28 import java.lang.reflect.Method;
29
30 import java.util.Iterator;
31 import java.util.LinkedList;
32 import java.util.List;
33
34 import com.lonniepryor.blues.aop.After;
35 import com.lonniepryor.blues.aop.AfterReturning;
36 import com.lonniepryor.blues.aop.AfterThrowing;
37 import com.lonniepryor.blues.aop.Around;
38 import com.lonniepryor.blues.aop.Before;
39 import com.lonniepryor.blues.aop.Imposter;
40 import com.lonniepryor.blues.util.Types;
41
42 import net.sf.cglib.MethodProxy;
43
44 /***
45 * Models the interception logic for a single service method.
46 *
47 * @author Lonnie Pryor
48 * @version $Revision: 1.1 $
49 */
50 public final class Interceptor {
51 /*** The method to intercept. */
52 private final Method method;
53 /*** The target we're pointing at. */
54 private Target interceptorTarget;
55
56 /***
57 * Creates a new JoinPoint object.
58 *
59 * @param method The method to intercept.
60 */
61 Interceptor (Method method) {
62 this.method = method;
63 interceptorTarget = isRequired() ? new InvokeImposterTarget()
64 : (Target)new InvokeSuperTarget();
65 }
66
67 /***
68 * Returns true if this interceptor invokes an introduced method.
69 *
70 * @return True if this interceptor invokes an introduced method.
71 */
72 boolean isRequired () {
73 return Types.interfaces().isSatisfiedBy(method.getDeclaringClass());
74 }
75
76 /***
77 * Returns the method to intercept.
78 *
79 * @return The method to intercept.
80 */
81 Method getMethod () {
82 return method;
83 }
84
85 /***
86 * Allows this interceptor a chance to control the execution of its method.
87 *
88 * @param target The target object that was invoked.
89 * @param parameters The parameters to the target.
90 * @param proxy The method proxy.
91 *
92 * @return The return value for the intercepted method invocation.
93 */
94 Object interceptInvocation (
95 Object target, Object[] parameters, MethodProxy proxy)
96 throws Throwable {
97 return interceptorTarget.process(target, parameters, proxy);
98 }
99
100 /***
101 * Binds the supplied advice to this interceptor.
102 *
103 * @param allAdvice All instances of Advice to bind.
104 */
105 void bindAdvice (List allAdvice) {
106 if (allAdvice.isEmpty())
107 return;
108 List beforeAdvice = new LinkedList();
109 List afterAdvice = new LinkedList();
110 List afterReturningAdvice = new LinkedList();
111 List afterThrowingAdvice = new LinkedList();
112 List aroundAdvice = new LinkedList();
113 for (Iterator iter = allAdvice.iterator(); iter.hasNext();) {
114 Object adviceInstance = ((Advice)iter.next()).getComponentInstance();
115 if (adviceInstance instanceof Before)
116 beforeAdvice.add(adviceInstance);
117 if (adviceInstance instanceof After)
118 afterAdvice.add(adviceInstance);
119 if (adviceInstance instanceof AfterReturning)
120 afterReturningAdvice.add(adviceInstance);
121 if (adviceInstance instanceof AfterThrowing)
122 afterThrowingAdvice.add(adviceInstance);
123 if (adviceInstance instanceof Around)
124 aroundAdvice.add(adviceInstance);
125 }
126 if (!aroundAdvice.isEmpty())
127 interceptorTarget = new AroundAdviceTarget(
128 (Around[])aroundAdvice.toArray(new Around[aroundAdvice.size()]),
129 interceptorTarget);
130 if (!afterThrowingAdvice.isEmpty())
131 interceptorTarget = new AfterThrowingAdviceTarget(
132 (AfterThrowing[])afterThrowingAdvice.toArray(
133 new AfterThrowing[afterThrowingAdvice.size()]), interceptorTarget);
134 if (!afterReturningAdvice.isEmpty())
135 interceptorTarget = new AfterReturningAdviceTarget(
136 (AfterReturning[])afterReturningAdvice.toArray(
137 new AfterReturning[afterReturningAdvice.size()]), interceptorTarget);
138 if (!afterAdvice.isEmpty())
139 interceptorTarget = new AfterAdviceTarget(
140 (After[])afterAdvice.toArray(new After[afterAdvice.size()]),
141 interceptorTarget);
142 if (!beforeAdvice.isEmpty())
143 interceptorTarget = new BeforeAdviceTarget(
144 (Before[])beforeAdvice.toArray(new Before[beforeAdvice.size()]),
145 interceptorTarget);
146 }
147
148 /***
149 * Represents an invokable target of an interceptor.
150 *
151 * @author Lonnie Pryor
152 * @version $Revision: 1.1 $
153 */
154 private interface Target {
155 /***
156 * Allows this target a chance to control the execution of this interceptor's
157 * method.
158 *
159 * @param target The target object that was invoked.
160 * @param parameters The parameters to the target.
161 * @param proxy The method proxy.
162 *
163 * @return The return value for the intercepted method invocation.
164 */
165 Object process (Object target, Object[] parameters, MethodProxy proxy)
166 throws Throwable;
167 }
168
169 /***
170 * Target that invokes the concrete method on the instance.
171 *
172 * @author Lonnie Pryor
173 * @version $Revision: 1.1 $
174 */
175 private final class InvokeSuperTarget implements Target {
176 /* (non-Javadoc)
177 * @see com.lonniepryor.blues.sys.Interceptor.Target#process(java.lang.Object,
178 * java.lang.Object[], net.sf.cglib.MethodProxy)
179 */
180 public Object process (Object target, Object[] parameters, MethodProxy proxy)
181 throws Throwable {
182 return proxy.invokeSuper(target, parameters);
183 }
184 }
185
186 /***
187 * Target that invokes the Imposter method on the instance.
188 *
189 * @author Lonnie Pryor
190 * @version $Revision: 1.1 $
191 */
192 private final class InvokeImposterTarget implements Target {
193 /* (non-Javadoc)
194 * @see com.lonniepryor.blues.sys.Interceptor.Target#process(java.lang.Object,
195 * java.lang.Object[], net.sf.cglib.MethodProxy)
196 */
197 public Object process (Object target, Object[] parameters, MethodProxy proxy)
198 throws Throwable {
199 return ((Imposter)target).process(method, parameters);
200 }
201 }
202
203 /***
204 * Target that invokes before advice.
205 *
206 * @author Lonnie Pryor
207 * @version $Revision: 1.1 $
208 */
209 private final class BeforeAdviceTarget implements Target {
210 /*** The advice to invoke. */
211 private final Before[] advice;
212 /*** The next target in the chain. */
213 private final Target next;
214
215 /***
216 * Creates a new BeforeAdviceTarget object.
217 *
218 * @param advice The advice to invoke.
219 * @param next The next target in the chain.
220 */
221 BeforeAdviceTarget (Before[] advice, Target next) {
222 this.advice = advice;
223 this.next = next;
224 }
225
226 /* (non-Javadoc)
227 * @see com.lonniepryor.blues.sys.Interceptor.Target#process(java.lang.Object,
228 * java.lang.Object[], net.sf.cglib.MethodProxy)
229 */
230 public Object process (Object target, Object[] parameters, MethodProxy proxy)
231 throws Throwable {
232 for (int i = 0; i < advice.length; ++i)
233 advice[i].before(target, method, parameters);
234 return next.process(target, parameters, proxy);
235 }
236 }
237
238 /***
239 * Target that invokes after advice.
240 *
241 * @author Lonnie Pryor
242 * @version $Revision: 1.1 $
243 */
244 private final class AfterAdviceTarget implements Target {
245 /*** The advice to invoke. */
246 private final After[] advice;
247 /*** The next target in the chain. */
248 private final Target next;
249
250 /***
251 * Creates a new AfterAdviceTarget object.
252 *
253 * @param advice The advice to invoke.
254 * @param next The next target in the chain.
255 */
256 AfterAdviceTarget (After[] advice, Target next) {
257 this.advice = advice;
258 this.next = next;
259 }
260
261 /* (non-Javadoc)
262 * @see com.lonniepryor.blues.sys.Interceptor.Target#process(java.lang.Object,
263 * java.lang.Object[], net.sf.cglib.MethodProxy)
264 */
265 public Object process (Object target, Object[] parameters, MethodProxy proxy)
266 throws Throwable {
267 try {
268 return next.process(target, parameters, proxy);
269 } finally {
270 for (int i = 0; i < advice.length; ++i)
271 advice[i].after(target, method, parameters);
272 }
273 }
274 }
275
276 /***
277 * Target that invokes after returning advice.
278 *
279 * @author Lonnie Pryor
280 * @version $Revision: 1.1 $
281 */
282 private final class AfterReturningAdviceTarget implements Target {
283 /*** The advice to invoke. */
284 private final AfterReturning[] advice;
285 /*** The next target in the chain. */
286 private final Target next;
287
288 /***
289 * Creates a new AfterReturningAdviceTarget object.
290 *
291 * @param advice The advice to invoke.
292 * @param next The next target in the chain.
293 */
294 AfterReturningAdviceTarget (AfterReturning[] advice, Target next) {
295 this.advice = advice;
296 this.next = next;
297 }
298
299 /* (non-Javadoc)
300 * @see com.lonniepryor.blues.sys.Interceptor.Target#process(java.lang.Object,
301 * java.lang.Object[], net.sf.cglib.MethodProxy)
302 */
303 public Object process (Object target, Object[] parameters, MethodProxy proxy)
304 throws Throwable {
305 Object result = next.process(target, parameters, proxy);
306 for (int i = 0; i < advice.length; ++i)
307 advice[i].afterReturning(target, method, parameters, result);
308 return result;
309 }
310 }
311
312 /***
313 * Target that invokes after returning advice.
314 *
315 * @author Lonnie Pryor
316 * @version $Revision: 1.1 $
317 */
318 private final class AfterThrowingAdviceTarget implements Target {
319 /*** The advice to invoke. */
320 private final AfterThrowing[] advice;
321 /*** The next target in the chain. */
322 private final Target next;
323
324 /***
325 * Creates a new AfterThrowingAdviceTarget object.
326 *
327 * @param advice The advice to invoke.
328 * @param next The next target in the chain.
329 */
330 AfterThrowingAdviceTarget (AfterThrowing[] advice, Target next) {
331 this.advice = advice;
332 this.next = next;
333 }
334
335 /* (non-Javadoc)
336 * @see com.lonniepryor.blues.sys.Interceptor.Target#process(java.lang.Object,
337 * java.lang.Object[], net.sf.cglib.MethodProxy)
338 */
339 public Object process (Object target, Object[] parameters, MethodProxy proxy)
340 throws Throwable {
341 try {
342 return next.process(target, parameters, proxy);
343 } catch (Throwable thrown) {
344 for (int i = 0; i < advice.length; ++i)
345 advice[i].afterThrowing(target, method, parameters, thrown);
346 throw thrown;
347 }
348 }
349 }
350
351 /***
352 * Target that invokes around advice.
353 *
354 * @author Lonnie Pryor
355 * @version $Revision: 1.1 $
356 */
357 private final class AroundAdviceTarget implements Target {
358 /*** The advice to invoke. */
359 private final Around[] advice;
360 /*** The next target in the chain. */
361 private final Target next;
362
363 /***
364 * Creates a new AroundAdviceTarget object.
365 *
366 * @param advice The advice to invoke.
367 * @param next The next target in the chain.
368 */
369 AroundAdviceTarget (Around[] advice, Target next) {
370 this.advice = advice;
371 this.next = next;
372 }
373
374 /* (non-Javadoc)
375 * @see com.lonniepryor.blues.sys.Interceptor.Target#process(java.lang.Object,
376 * java.lang.Object[], net.sf.cglib.MethodProxy)
377 */
378 public Object process (
379 final Object target, final Object[] parameters, final MethodProxy proxy)
380 throws Throwable {
381 return advice[0].around(
382 target, method, parameters,
383 new Around.InvoctionChain() {
384 int index = 0;
385
386 public Object invokeNext ()
387 throws Throwable {
388 ++index;
389 return (index < advice.length)
390 ? advice[index].around(target, method, parameters, this)
391 : next.process(target, parameters, proxy);
392 }
393 });
394 }
395 }
396 }
This page was automatically generated by Maven