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    }