001: /*
002: * Copyright 2002-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.aop.interceptor;
018:
019: import java.io.Serializable;
020:
021: import org.aopalliance.intercept.MethodInterceptor;
022: import org.aopalliance.intercept.MethodInvocation;
023:
024: import org.springframework.aop.Advisor;
025: import org.springframework.aop.support.DefaultPointcutAdvisor;
026:
027: /**
028: * Interceptor that exposes the current MethodInvocation.
029: * We occasionally need to do this; for example, when a pointcut
030: * or target object needs to know the Invocation context.
031: *
032: * <p>Don't use this interceptor unless this is really necessary.
033: * Target objects should not normally know about Spring AOP,
034: * as this creates a dependency on Spring. Target objects
035: * should be plain POJOs as far as possible.
036: *
037: * <p>If used, this interceptor will normally be the first
038: * in the interceptor chain.
039: *
040: * @author Rod Johnson
041: */
042: public class ExposeInvocationInterceptor implements MethodInterceptor,
043: Serializable {
044:
045: /** Singleton instance of this class */
046: public static final ExposeInvocationInterceptor INSTANCE = new ExposeInvocationInterceptor();
047:
048: /**
049: * Singleton advisor for this class. Use in preference to INSTANCE when using
050: * Spring AOP, as it prevents the need to create a new Advisor to wrap the instance.
051: */
052: public static final Advisor ADVISOR = new DefaultPointcutAdvisor(
053: INSTANCE) {
054: public int getOrder() {
055: return Integer.MIN_VALUE;
056: }
057:
058: public String toString() {
059: return ExposeInvocationInterceptor.class.getName()
060: + ".ADVISOR";
061: }
062: };
063:
064: private static final ThreadLocal invocation = new ThreadLocal();
065:
066: /**
067: * Return the AOP Alliance MethodInvocation object associated with the current invocation.
068: * @return the invocation object associated with the current invocation
069: * @throws IllegalStateException if there is no AOP invocation in progress,
070: * or if the ExposeInvocationInterceptor was not added to this interceptor chain
071: */
072: public static MethodInvocation currentInvocation()
073: throws IllegalStateException {
074: MethodInvocation mi = (MethodInvocation) invocation.get();
075: if (mi == null)
076: throw new IllegalStateException(
077: "No MethodInvocation found: Check that an AOP invocation is in progress, "
078: + "and that the ExposeInvocationInterceptor is in the interceptor chain.");
079: return mi;
080: }
081:
082: /**
083: * Ensure that only the canonical instance can be created.
084: */
085: private ExposeInvocationInterceptor() {
086: }
087:
088: public Object invoke(MethodInvocation mi) throws Throwable {
089: Object old = invocation.get();
090: invocation.set(mi);
091: try {
092: return mi.proceed();
093: } finally {
094: invocation.set(old);
095: }
096: }
097:
098: /**
099: * Required to support serialization. Replaces with canonical instance
100: * on deserialization, protecting Singleton pattern.
101: * Alternative to overriding the <code>equals</code> method.
102: */
103: private Object readResolve() {
104: return INSTANCE;
105: }
106:
107: }
|