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 * @see org.apache.hivemind.ServiceInterceptorFactory#createInterceptor(org.apache.hivemind.InterceptorStack, org.apache.hivemind.internal.Module, java.util.List)
043 */
044 public void createInterceptor(InterceptorStack stack, Module invokingModule, Object parameters)
045 {
046 final Object parameter = ((List) parameters).get( 0 );
047 Defense.isAssignable( parameter, MethodInterceptor.class, "Implementation Object" );
048 MethodInterceptor methodInterceptor = ( MethodInterceptor )parameter;
049 createInterceptor(stack, invokingModule, methodInterceptor);
050 }
051
052 /**
053 * @see org.apache.hivemind.ServiceInterceptorFactory#createInterceptor(org.apache.hivemind.InterceptorStack, org.apache.hivemind.internal.Module, java.util.List)
054 */
055 public void createInterceptor(InterceptorStack stack, Module invokingModule, MethodInterceptor methodInterceptor)
056 {
057 final Class[] interfaces = new Class[]{stack.getServiceInterface()};
058 final ClassLoader classLoader = invokingModule.getClassResolver().getClassLoader();
059 final InvocationHandler invocationHandler = new MethodInterceptorInvocationHandler( methodInterceptor, stack );
060 stack.push( Proxy.newProxyInstance( classLoader, interfaces, invocationHandler ) );
061 }
062
063 /**
064 * A java proxy InvocationHandler implementation which allows a MethodInterceptor to intercept the method invocation.
065 */
066 private final class MethodInterceptorInvocationHandler implements InvocationHandler
067 {
068 private final MethodInterceptor methodInterceptor;
069 private final InterceptorStack stack;
070 private final Object target;
071
072 /**
073 * Constructs a MethodInterceptorInvocationHandler
074 *
075 * @param stack the interceptor stack
076 */
077 public MethodInterceptorInvocationHandler( MethodInterceptor methodInterceptor, InterceptorStack stack )
078 {
079 this.stack = stack;
080 this.target = stack.peek();
081 this.methodInterceptor = methodInterceptor;
082 }
083
084 /**
085 * Calls the MethodInterceptor's invoke method.
086 * @param proxy a reference to the proxy instance
087 * @param method the method being invoked
088 * @param args the arguments to the method
089 * @return the value returned by the MethodInterceptor
090 * @throws Throwable
091 */
092 public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable
093 {
094 return methodInterceptor.invoke( new MethodInvocationImpl( target, method, args, stack.peek() ) );
095 }
096 }
097
098 /**
099 * A java reflection-based implementation of a MethodInvocation
100 */
101 private final class MethodInvocationImpl implements MethodInvocation
102 {
103 private final Object next;
104 private final Method method;
105 private final Object[] arguments;
106 private final Object proxy;
107
108 /**
109 * Constructs a MethodInvocationImpl object.
110 *
111 * @param next the next object
112 * @param method the method
113 * @param arguments the arguments
114 * @param proxy the outermost proxy object (allows calling another method instead).
115 */
116 public MethodInvocationImpl( Object next, Method method, Object[] arguments, Object proxy )
117 {
118 this.next = next;
119 this.method = method;
120 this.arguments = arguments;
121 this.proxy = proxy;
122 }
123
124 /**
125 * Invokes the method on the next object.
126 *
127 * @return value returned by invoking the method on the next object
128 * @throws Throwable throwable thrown by invoking method on the next object
129 */
130 public final Object proceed() throws Throwable
131 {
132 try
133 {
134 return method.invoke( next, arguments );
135 }
136 catch( InvocationTargetException e )
137 {
138 throw e.getTargetException();
139 }
140 }
141
142 public final Method getMethod()
143 {
144 return method;
145 }
146
147 public final AccessibleObject getStaticPart()
148 {
149 return method;
150 }
151
152 public final Object getThis()
153 {
154 return proxy;
155 }
156
157 public final Object[] getArguments()
158 {
159 return arguments;
160 }
161 }
162 }