1 package org.apache.fulcrum.yaafi.framework.interceptor;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.lang.reflect.InvocationHandler;
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25
26 import org.apache.fulcrum.yaafi.framework.util.ReadWriteLock;
27 import org.apache.fulcrum.yaafi.framework.util.Validate;
28
29 /**
30 * The InvocationHandler invoked when a service call is routed through
31 * the dynamic proxy.
32 *
33 * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl </a>
34 */
35
36 public class AvalonInterceptorInvocationHandler implements InvocationHandler
37 {
38 /** the name of the service */
39 private String serviceName;
40
41 /** the shorthand of the service */
42 private String serviceShorthand;
43
44 /** the real service implementation */
45 private Object serviceDelegate;
46
47 /** the list of interceptors to be invoked */
48 private AvalonInterceptorService [] serviceInterceptorList;
49
50 /** read/write lock to snychronize access to services */
51 private ReadWriteLock readWriteLock;
52
53 /** counts the current transactions */
54 private static volatile long transactionCounter = 0L;
55
56 /** the current transaction id */
57 private Long transactionId;
58
59 /**
60 * Constructor.
61 *
62 * @param serviceName the name of the service
63 * @param serviceShorthand the shorthand of the service being intercepted
64 * @param serviceDelegate the real service implementation
65 * @param serviceInterceptorList the list of interceptors to be invoked
66 * @param readWriteLock the YAAFI kernel lock
67 */
68 public AvalonInterceptorInvocationHandler(
69 String serviceName,
70 String serviceShorthand,
71 Object serviceDelegate,
72 AvalonInterceptorService [] serviceInterceptorList,
73 ReadWriteLock readWriteLock )
74 {
75 Validate.notEmpty(serviceName,"serviceName");
76 Validate.notEmpty(serviceShorthand,"serviceShorthand");
77 Validate.notNull(serviceDelegate,"serviceDelegate");
78 Validate.notNull(serviceInterceptorList,"serviceInterceptorList");
79 Validate.notNull(readWriteLock,"readWriteLock");
80
81 this.serviceName = serviceName;
82 this.serviceShorthand = serviceShorthand;
83 this.serviceDelegate = serviceDelegate;
84 this.serviceInterceptorList = serviceInterceptorList;
85 this.readWriteLock = readWriteLock;
86 }
87
88 /**
89 * @return Returns the delegate.
90 */
91 public Object getServiceDelegate()
92 {
93 return this.serviceDelegate;
94 }
95
96 /**
97 * @return Returns the serviceInterceptorList.
98 */
99 public AvalonInterceptorService [] getServiceInterceptorList()
100 {
101 return serviceInterceptorList;
102 }
103
104 /**
105 * @return Returns the serviceName.
106 */
107 public String getServiceName()
108 {
109 return serviceName;
110 }
111
112 /**
113 * @return Returns the serviceShorthand.
114 */
115 public String getServiceShorthand()
116 {
117 return serviceShorthand;
118 }
119
120 /**
121 * @return Returns the transaction id
122 */
123 public Long getTransactionId()
124 {
125 return transactionId;
126 }
127
128 /**
129 * @see java.lang.Object#toString()
130 */
131 public String toString()
132 {
133 return super.toString();
134 }
135
136 /**
137 * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
138 */
139 public Object invoke(Object proxy, Method method, Object [] args)
140 throws Throwable
141 {
142 Object result = null;
143 Object lock = null;
144
145
146
147 AvalonInterceptorContext context = new AvalonInterceptorContextImpl(
148 this.getServiceName(),
149 this.getServiceShorthand(),
150 this.getServiceDelegate(),
151 method,
152 args
153 );
154
155
156
157 boolean hasCreatedTransaction = this.createTransactionId(context);
158
159 try
160 {
161 context.incrementInvocationDepth();
162 lock = this.getReadWriteLock().getReadLock(this.serviceName);
163 this.onEntry(context);
164 result = method.invoke( this.getServiceDelegate(), args );
165 this.onExit(context,result);
166 return result;
167 }
168 catch (InvocationTargetException e)
169 {
170 this.onError(context,e.getTargetException());
171 throw e.getTargetException();
172 }
173 catch (Throwable t)
174 {
175 throw t;
176 }
177 finally
178 {
179
180
181 this.getReadWriteLock().releaseLock(lock,this.serviceName);
182
183
184
185 context.decrementInvocationDepth();
186
187
188
189 if( hasCreatedTransaction )
190 {
191 context.clearTransactionId();
192 }
193 }
194 }
195
196 /**
197 * Invoke the onEntry method on all service interceptors.
198 *
199 * @param context the current interceptor context
200 */
201 private void onEntry( AvalonInterceptorContext context )
202 {
203 for( int i=0; i<this.getServiceInterceptorList().length; i++ )
204 {
205 this.getServiceInterceptorList()[i].onEntry(context);
206 }
207 }
208
209 /**
210 * Invoke the onExit method on all service interceptors.
211 *
212 * @param context the current interceptor context
213 * @param result the result
214 */
215 private void onExit( AvalonInterceptorContext context, Object result )
216 {
217 for( int i=this.getServiceInterceptorList().length-1; i>=0; i-- )
218 {
219 this.getServiceInterceptorList()[i].onExit(context,result);
220 }
221 }
222
223 /**
224 * Invoke the onError method on all service interceptors.
225 *
226 * @param context the current interceptor context
227 * @param t the resulting exception
228 */
229 private void onError( AvalonInterceptorContext context, Throwable t )
230 {
231 for( int i=this.getServiceInterceptorList().length-1; i>=0; i-- )
232 {
233 this.getServiceInterceptorList()[i].onError(context,t);
234 }
235 }
236
237 /**
238 * @return Returns the readWriteLock.
239 */
240 private final ReadWriteLock getReadWriteLock()
241 {
242 return readWriteLock;
243 }
244
245 /**
246 * Creates a transaction id using the thread local storage
247 * @param context current interceptor context
248 * @return was a new transaction started
249 */
250 private boolean createTransactionId(AvalonInterceptorContext context)
251 {
252 Long currentTransactionId = null;
253
254 if( context.hasTransactionId() == false )
255 {
256
257
258 currentTransactionId = new Long(
259 ++AvalonInterceptorInvocationHandler.transactionCounter
260 );
261
262
263
264 context.setTransactionId(currentTransactionId);
265
266 return true;
267 }
268
269 return false;
270 }
271 }