001 // Copyright 2004, 2005 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.hivemind.lib.impl;
016
017 import java.lang.reflect.AccessibleObject;
018 import java.lang.reflect.InvocationHandler;
019 import java.lang.reflect.InvocationTargetException;
020 import java.lang.reflect.Method;
021 import java.lang.reflect.Proxy;
022 import java.util.List;
023
024 import org.aopalliance.intercept.MethodInterceptor;
025 import org.aopalliance.intercept.MethodInvocation;
026 import org.apache.hivemind.InterceptorStack;
027 import org.apache.hivemind.ServiceInterceptorFactory;
028 import org.apache.hivemind.impl.BaseLocatable;
029 import org.apache.hivemind.internal.Module;
030 import org.apache.hivemind.util.Defense;
031
032 /**
033 * A service interceptor factory supporting the AOP Alliance MethodInterceptor interface.
034 * <b>Note:</b>The current implementation uses JDK proxies as opposed to Javassist!
035 * @author James Carman
036 * @since 1.1
037 */
038 public class MethodInterceptorFactory extends BaseLocatable implements ServiceInterceptorFactory
039 {
040
041 /**
042 *
043 * @see org.apache.hivemind.ServiceInterceptorFactory#createInterceptor(org.apache.hivemind.InterceptorStack, org.apache.hivemind.internal.Module, java.util.List)
044 */
045 public void createInterceptor(InterceptorStack stack, Module invokingModule, List parameters)
046 {
047 final Class[] interfaces = new Class[]{stack.getServiceInterface()};
048 final ClassLoader classLoader = invokingModule.getClassResolver().getClassLoader();
049 final Object parameter = parameters.get( 0 );
050 Defense.isAssignable( parameter, MethodInterceptor.class, "Implementation Object" );
051 MethodInterceptor methodInterceptor = ( MethodInterceptor )parameter;
052 final InvocationHandler invocationHandler = new MethodInterceptorInvocationHandler( methodInterceptor, stack );
053 stack.push( Proxy.newProxyInstance( classLoader, interfaces, invocationHandler ) );
054 }
055
056 /**
057 * A java proxy InvocationHandler implementation which allows a MethodInterceptor to intercept the method invocation.
058 */
059 private final class MethodInterceptorInvocationHandler implements InvocationHandler
060 {
061 private final MethodInterceptor methodInterceptor;
062 private final InterceptorStack stack;
063 private final Object target;
064
065 /**
066 * Constructs a MethodInterceptorInvocationHandler
067 *
068 * @param stack the interceptor stack
069 */
070 public MethodInterceptorInvocationHandler( MethodInterceptor methodInterceptor, InterceptorStack stack )
071 {
072 this.stack = stack;
073 this.target = stack.peek();
074 this.methodInterceptor = methodInterceptor;
075 }
076
077 /**
078 * Calls the MethodInterceptor's invoke method.
079 * @param proxy a reference to the proxy instance
080 * @param method the method being invoked
081 * @param args the arguments to the method
082 * @return the value returned by the MethodInterceptor
083 * @throws Throwable
084 */
085 public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable
086 {
087 return methodInterceptor.invoke( new MethodInvocationImpl( target, method, args, stack.peek() ) );
088 }
089 }
090
091 /**
092 * A java reflection-based implementation of a MethodInvocation
093 */
094 private final class MethodInvocationImpl implements MethodInvocation
095 {
096 private final Object next;
097 private final Method method;
098 private final Object[] arguments;
099 private final Object proxy;
100
101 /**
102 * Constructs a MethodInvocationImpl object.
103 *
104 * @param next the next object
105 * @param method the method
106 * @param arguments the arguments
107 * @param proxy the outermost proxy object (allows calling another method instead).
108 */
109 public MethodInvocationImpl( Object next, Method method, Object[] arguments, Object proxy )
110 {
111 this.next = next;
112 this.method = method;
113 this.arguments = arguments;
114 this.proxy = proxy;
115 }
116
117 /**
118 * Invokes the method on the next object.
119 *
120 * @return value returned by invoking the method on the next object
121 * @throws Throwable throwable thrown by invoking method on the next object
122 */
123 public final Object proceed() throws Throwable
124 {
125 try
126 {
127 return method.invoke( next, arguments );
128 }
129 catch( InvocationTargetException e )
130 {
131 throw e.getTargetException();
132 }
133 }
134
135 public final Method getMethod()
136 {
137 return method;
138 }
139
140 public final AccessibleObject getStaticPart()
141 {
142 return method;
143 }
144
145 public final Object getThis()
146 {
147 return proxy;
148 }
149
150 public final Object[] getArguments()
151 {
152 return arguments;
153 }
154 }
155 }