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 }