001 package org.apache.fulcrum.yaafi.framework.interceptor;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.lang.reflect.Method;
023 import java.util.HashMap;
024 import java.util.Map;
025
026 import org.apache.fulcrum.yaafi.framework.tls.ThreadLocalStorage;
027 import org.apache.fulcrum.yaafi.framework.tls.ThreadLocalStorageImpl;
028 import org.apache.fulcrum.yaafi.framework.util.ToStringBuilder;
029 import org.apache.fulcrum.yaafi.framework.util.Validate;
030
031 /**
032 * Contains context information for the interceptors being invoked. The
033 * class contains a request context which allows to store data from within an
034 * interceptor. It also provides access to a ThreadLocalStorage to associate
035 * data with the current thread.
036 *
037 * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
038 */
039
040 public class AvalonInterceptorContextImpl implements AvalonInterceptorContext
041 {
042 /** key for looking up the transaction id */
043 private static final String TRANSACTIONID_KEY =
044 "$org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext#transactionId";
045
046 /** key for looking up the service invocation depth */
047 private static final String INVOCATIONDEPTH_KEY =
048 "$org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorContext#invocationDepth";
049
050 /** the name of the service being intercepted */
051 private String serviceName;
052
053 /** the shorthand of the service being intercepted */
054 private String serviceShorthand;
055
056 /** the real service implementation */
057 private Object serviceDelegate;
058
059 /** the method being invoked */
060 private Method method;
061
062 /** the arguments for the method invocation */
063 private Object[] args;
064
065 /** context information associated with the current invocation */
066 private HashMap requestContext;
067
068 /** context information associated with the current thread */
069 private static ThreadLocalStorageImpl tls = new ThreadLocalStorageImpl();
070
071 /** works as invocation counter */
072 private static volatile long invocationCounter = 0L;
073
074 /** the associated transaction id */
075 private Long invocationId;
076
077 /**
078 * Constructor.
079 *
080 * @param serviceName the name of the service being intercepted
081 * @param serviceShorthand the shorthand of the service being intercepted
082 * @param serviceDelegate the real service implementation
083 * @param method the method being invoked
084 * @param args the list of arguments for the method invocation
085 */
086 public AvalonInterceptorContextImpl(
087 String serviceName, String serviceShorthand, Object serviceDelegate, Method method, Object[] args )
088 {
089 Validate.notEmpty(serviceName,"serviceName");
090 Validate.notEmpty(serviceShorthand,"serviceShorthand");
091 Validate.notNull(serviceDelegate,"serviceDelegate");
092 Validate.notNull(method,"method");
093
094 this.invocationId = new Long(++AvalonInterceptorContextImpl.invocationCounter);
095 this.serviceName = serviceName;
096 this.serviceShorthand = serviceShorthand;
097 this.serviceDelegate = serviceDelegate;
098 this.method = method;
099 this.args = args;
100 this.requestContext = new HashMap();
101 }
102
103 /**
104 * @return Returns the context for the given request.
105 */
106 public final Map getRequestContext()
107 {
108 return requestContext;
109 }
110
111 /**
112 * @return Returns the serviceDelegate.
113 */
114 public final Object getServiceDelegate()
115 {
116 return serviceDelegate;
117 }
118
119 /**
120 * @return Returns the serviceName.
121 */
122 public final String getServiceName()
123 {
124 return serviceName;
125 }
126
127 /**
128 * @return Returns the serviceShorthand.
129 */
130 public String getServiceShorthand()
131 {
132 return serviceShorthand;
133 }
134
135 /**
136 * @return Returns the args.
137 */
138 public final Object [] getArgs()
139 {
140 return args;
141 }
142
143 /**
144 * @return Returns the method.
145 */
146 public final Method getMethod()
147 {
148 return method;
149 }
150
151 /**
152 * @return Returns the ThreadLocalStorage
153 */
154 public final ThreadLocalStorage getThreadContext()
155 {
156 return AvalonInterceptorContextImpl.tls;
157 }
158
159 /**
160 * @return is a transaction id defined for the current thread
161 */
162 public boolean hasTransactionId()
163 {
164 return ( this.getTransactionId() != null ? true : false );
165 }
166
167 /**
168 * @return get the transaction id defined for the current thread
169 */
170 public Object getTransactionId()
171 {
172 return this.getThreadContext().get(TRANSACTIONID_KEY);
173 }
174
175 /**
176 * Set the transaction id for the current thread.
177 * @param transactionId the transaction id
178 */
179 public void setTransactionId( Object transactionId )
180 {
181 this.getThreadContext().put(TRANSACTIONID_KEY,transactionId);
182 }
183
184 /**
185 * Clears the transaction id for the current thread.
186 */
187 public void clearTransactionId()
188 {
189 this.setTransactionId(null);
190 }
191
192 /**
193 * Increment the current service invocation depth
194 */
195 public void incrementInvocationDepth()
196 {
197 Integer invocationDepth = (Integer) this.getThreadContext().get(INVOCATIONDEPTH_KEY);
198
199 if( invocationDepth != null )
200 {
201 int currInvocationDepth = invocationDepth.intValue();
202 this.getThreadContext().put(INVOCATIONDEPTH_KEY, new Integer(++currInvocationDepth));
203 }
204 else
205 {
206 this.getThreadContext().put(INVOCATIONDEPTH_KEY, new Integer(0));
207 }
208 }
209
210 /**
211 * Decrement the current service invocation depth
212 */
213 public void decrementInvocationDepth()
214 {
215 Integer invocationDepth = (Integer) this.getThreadContext().get(INVOCATIONDEPTH_KEY);
216
217 if( invocationDepth != null )
218 {
219 int currInvocationDepth = invocationDepth.intValue();
220 this.getThreadContext().put(INVOCATIONDEPTH_KEY, new Integer(--currInvocationDepth));
221 }
222 }
223
224 /**
225 * Get the current service invocation depth
226 * @return the current service invocation depth
227 */
228 public int getInvocationDepth()
229 {
230 Integer invocationDepth = (Integer) this.getThreadContext().get(INVOCATIONDEPTH_KEY);
231
232 if( invocationDepth != null )
233 {
234 return invocationDepth.intValue();
235 }
236 else
237 {
238 return 0;
239 }
240 }
241
242 /**
243 * @return Returns the invocationId.
244 */
245 public final Long getInvocationId()
246 {
247 return invocationId;
248 }
249
250 /**
251 * @see java.lang.Object#toString()
252 */
253 public String toString()
254 {
255 ToStringBuilder toStringBuilder = new ToStringBuilder(this);
256
257 toStringBuilder.append("serviceShorthand",this.serviceShorthand);
258 toStringBuilder.append("serviceName",this.serviceName);
259 toStringBuilder.append("serviceDelegate",this.serviceDelegate);
260 toStringBuilder.append("method",this.method.getName());
261 toStringBuilder.append("args",this.args.length);
262 toStringBuilder.append("transactionId",this.getTransactionId());
263 toStringBuilder.append("invocationId",this.invocationId);
264 toStringBuilder.append("invocationDepth",this.getInvocationDepth());
265 toStringBuilder.append("requestContext",this.requestContext);
266
267 return toStringBuilder.toString();
268 }
269 }