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 }