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 }