| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.commons.proxy; |
| |
| import java.lang.reflect.InvocationHandler; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Proxy; |
| |
| /** |
| * A <code>ProxyFactory</code> can be used to create three different "flavors" of proxy objects. |
| * |
| * <ul> |
| * <li>Delegator - the proxy will delegate to an object provided by an {@link ObjectProvider}</li> |
| * <li>Interceptor - the proxy will pass each method invocation through an {@link Interceptor}</li> |
| * <li>Invoker - the proxy will allow an {@link Invoker} to handle all method invocations</li> |
| * </ul> |
| * |
| * <p> |
| * Originally, the ProxyFactory class was an interface. However, to allow for future changes to the |
| * class without breaking binary or semantic compatibility, it has been changed to a concrete class. |
| * |
| * </p> |
| * <p> |
| * <b>Note</b>: This class uses Java reflection. For more efficient proxies, try using either |
| * {@link org.apache.commons.proxy.factory.cglib.CglibProxyFactory CglibProxyFactory} or |
| * {@link org.apache.commons.proxy.factory.javassist.JavassistProxyFactory JavassistProxyFactory} instead. |
| * </p> |
| * @author James Carman |
| * @since 1.0 |
| */ |
| public class ProxyFactory |
| { |
| //---------------------------------------------------------------------------------------------------------------------- |
| // Other Methods |
| //---------------------------------------------------------------------------------------------------------------------- |
| |
| /** |
| * Returns true if all <code>proxyClasses</code> are interfaces. |
| * |
| * @param proxyClasses the proxy classes |
| * @return true if all <code>proxyClasses</code> are interfaces |
| */ |
| public boolean canProxy( Class[] proxyClasses ) |
| { |
| for( int i = 0; i < proxyClasses.length; i++ ) |
| { |
| Class proxyClass = proxyClasses[i]; |
| if( !proxyClass.isInterface() ) |
| { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Creates a proxy which delegates to the object provided by <code>delegateProvider</code>. The proxy will be |
| * generated using the current thread's "context class loader." |
| * |
| * @param delegateProvider the delegate provider |
| * @param proxyClasses the interfaces that the proxy should implement |
| * @return a proxy which delegates to the object provided by the target object provider |
| */ |
| public Object createDelegatorProxy( ObjectProvider delegateProvider, Class[] proxyClasses ) |
| { |
| return createDelegatorProxy( Thread.currentThread().getContextClassLoader(), delegateProvider, proxyClasses ); |
| } |
| |
| /** |
| * Creates a proxy which delegates to the object provided by <code>delegateProvider</code>. |
| * |
| * @param classLoader the class loader to use when generating the proxy |
| * @param delegateProvider the delegate provider |
| * @param proxyClasses the interfaces that the proxy should implement |
| * @return a proxy which delegates to the object provided by the target <code>delegateProvider> |
| */ |
| public Object createDelegatorProxy( ClassLoader classLoader, ObjectProvider delegateProvider, |
| Class[] proxyClasses ) |
| { |
| return Proxy.newProxyInstance( classLoader, proxyClasses, |
| new DelegatorInvocationHandler( delegateProvider ) ); |
| } |
| |
| /** |
| * Creates a proxy which passes through a {@link Interceptor interceptor} before eventually reaching the |
| * <code>target</code> object. The proxy will be generated using the current thread's "context class loader." |
| * |
| * @param target the target object |
| * @param interceptor the method interceptor |
| * @param proxyClasses the interfaces that the proxy should implement |
| * @return a proxy which passes through a {@link Interceptor interceptor} before eventually reaching the |
| * <code>target</code> object. |
| */ |
| public Object createInterceptorProxy( Object target, Interceptor interceptor, |
| Class[] proxyClasses ) |
| { |
| return createInterceptorProxy( Thread.currentThread().getContextClassLoader(), target, interceptor, |
| proxyClasses ); |
| } |
| |
| /** |
| * Creates a proxy which passes through a {@link Interceptor interceptor} before eventually reaching the |
| * <code>target</code> object. |
| * |
| * @param classLoader the class loader to use when generating the proxy |
| * @param target the target object |
| * @param interceptor the method interceptor |
| * @param proxyClasses the interfaces that the proxy should implement. |
| * @return a proxy which passes through a {@link Interceptor interceptor} before eventually reaching the |
| * <code>target</code> object. |
| */ |
| public Object createInterceptorProxy( ClassLoader classLoader, Object target, Interceptor interceptor, |
| Class[] proxyClasses ) |
| { |
| return Proxy |
| .newProxyInstance( classLoader, proxyClasses, new InterceptorInvocationHandler( target, interceptor ) ); |
| } |
| |
| /** |
| * Creates a proxy which uses the provided {@link Invoker} to handle all method invocations. The proxy will be |
| * generated using the current thread's "context class loader." |
| * |
| * @param invoker the invoker |
| * @param proxyClasses the interfaces that the proxy should implement |
| * @return a proxy which uses the provided {@link Invoker} to handle all method invocations |
| */ |
| public Object createInvokerProxy( Invoker invoker, Class[] proxyClasses ) |
| { |
| return createInvokerProxy( Thread.currentThread().getContextClassLoader(), invoker, |
| proxyClasses ); |
| } |
| |
| /** |
| * Creates a proxy which uses the provided {@link Invoker} to handle all method invocations. |
| * |
| * @param classLoader the class loader to use when generating the proxy |
| * @param invoker the invoker |
| * @param proxyClasses the interfaces that the proxy should implement |
| * @return a proxy which uses the provided {@link Invoker} to handle all method invocations |
| */ |
| public Object createInvokerProxy( ClassLoader classLoader, Invoker invoker, |
| Class[] proxyClasses ) |
| { |
| return Proxy.newProxyInstance( classLoader, proxyClasses, new InvokerInvocationHandler( invoker ) ); |
| } |
| |
| //---------------------------------------------------------------------------------------------------------------------- |
| // Inner Classes |
| //---------------------------------------------------------------------------------------------------------------------- |
| |
| private static class DelegatorInvocationHandler implements InvocationHandler |
| { |
| private final ObjectProvider delegateProvider; |
| protected DelegatorInvocationHandler( ObjectProvider delegateProvider ) |
| { |
| this.delegateProvider = delegateProvider; |
| } |
| |
| public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable |
| { |
| try |
| { |
| return method.invoke( delegateProvider.getObject(), args ); |
| } |
| catch( InvocationTargetException e ) |
| { |
| throw e.getTargetException(); |
| } |
| } |
| } |
| |
| private static class InterceptorInvocationHandler implements InvocationHandler |
| { |
| private final Object target; |
| private final Interceptor methodInterceptor; |
| public InterceptorInvocationHandler( Object target, Interceptor methodInterceptor ) |
| { |
| this.target = target; |
| this.methodInterceptor = methodInterceptor; |
| } |
| |
| public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable |
| { |
| final ReflectionInvocation invocation = new ReflectionInvocation( target, method, args ); |
| return methodInterceptor.intercept( invocation ); |
| } |
| } |
| |
| private static class ReflectionInvocation implements Invocation |
| { |
| private final Method method; |
| private final Object[] arguments; |
| private final Object target; |
| public ReflectionInvocation( Object target, Method method, Object[] arguments ) |
| { |
| this.method = method; |
| this.arguments = ( arguments == null ? ProxyUtils.EMPTY_ARGUMENTS : arguments ); |
| this.target = target; |
| } |
| |
| public Object[] getArguments() |
| { |
| return arguments; |
| } |
| |
| public Method getMethod() |
| { |
| return method; |
| } |
| |
| public Object getProxy() |
| { |
| return target; |
| } |
| |
| public Object proceed() throws Throwable |
| { |
| try |
| { |
| return method.invoke( target, arguments ); |
| } |
| catch( InvocationTargetException e ) |
| { |
| throw e.getTargetException(); |
| } |
| } |
| } |
| |
| private static class InvokerInvocationHandler implements InvocationHandler |
| { |
| private final Invoker invoker; |
| public InvokerInvocationHandler( Invoker invoker ) |
| { |
| this.invoker = invoker; |
| } |
| |
| public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable |
| { |
| return invoker.invoke( proxy, method, args ); |
| } |
| } |
| } |
| |