001package org.javasimon.proxy;
002
003import java.lang.reflect.InvocationHandler;
004import java.lang.reflect.Method;
005import java.lang.reflect.Proxy;
006
007/**
008 * Produces proxy that wrap and existing class using {@link java.lang.reflect.Proxy} class.
009 * This class is used to do lightweight AOP.
010 *
011 * @param <T> Type of the wrapped class
012 * @author gerald
013 */
014public class DelegatingProxyFactory<T> implements InvocationHandler, Delegating<T> {
015
016        /** Wrapped class and concrete implementation. */
017        private final T delegate;
018
019        /**
020         * Main constructor.
021         *
022         * @param delegate Wrapped class and concrete implementation
023         */
024        public DelegatingProxyFactory(T delegate) {
025                super();
026                this.delegate = delegate;
027        }
028
029        public final Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
030                return invoke(new DelegatingMethodInvocation<>(delegate, proxy, method, args));
031        }
032
033        /**
034         * Method to override in child classes.
035         *
036         * @param delegatingMethodInvocation Method invocation (arguments, method name, etc.)
037         * @return Method invocation results
038         * @throws Throwable Method invocation raised exception
039         */
040        protected Object invoke(DelegatingMethodInvocation<T> delegatingMethodInvocation) throws Throwable {
041                return delegatingMethodInvocation.proceed();
042        }
043
044        /** Return Wrapped class and concrete implementation. */
045        public T getDelegate() {
046                return delegate;
047        }
048
049        /**
050         * Create a proxy using given classloader and interfaces
051         *
052         * @param classLoader Class loader
053         * @param interfaces Interfaces to implement
054         * @return Proxy
055         */
056        public Object newProxy(ClassLoader classLoader, Class<?>... interfaces) {
057                return Proxy.newProxyInstance(classLoader, interfaces, this);
058        }
059
060        /**
061         * Create a proxy using given classloader and interfaces.
062         * Current thread classloader is used as a default.
063         *
064         * @param interfaces Interfaces to implement
065         * @return Proxy
066         */
067        public Object newProxy(Class<?>... interfaces) {
068                return newProxy(Thread.currentThread().getContextClassLoader(), interfaces);
069        }
070
071        /**
072         * Create a proxy using given classloader and interfaces.
073         *
074         * @param interfaces Interface to implement
075         * @return proxy
076         */
077        public <X> X newProxy(Class<X> interfaces) {
078                return (X) newProxy(new Class[] {interfaces});
079        }
080}