View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.proxy2.jdk;
19  
20  import java.io.Serializable;
21  import java.lang.reflect.InvocationHandler;
22  import java.lang.reflect.InvocationTargetException;
23  import java.lang.reflect.Method;
24  import java.lang.reflect.Proxy;
25  
26  import org.apache.commons.lang3.ArrayUtils;
27  import org.apache.commons.lang3.ObjectUtils;
28  import org.apache.commons.proxy2.Interceptor;
29  import org.apache.commons.proxy2.Invocation;
30  import org.apache.commons.proxy2.Invoker;
31  import org.apache.commons.proxy2.ObjectProvider;
32  import org.apache.commons.proxy2.ProxyUtils;
33  import org.apache.commons.proxy2.impl.AbstractProxyFactory;
34  
35  /**
36   * {@link org.apache.commons.proxy2.ProxyFactory ProxyFactory} implementation that uses {@link java.lang.reflect.Proxy} proxies.
37   */
38  public class JdkProxyFactory extends AbstractProxyFactory
39  {
40      //******************************************************************************************************************
41      // ProxyFactory Implementation
42      //******************************************************************************************************************
43  
44      /**
45       * Creates a proxy2 which delegates to the object provided by <code>delegateProvider</code>.
46       * 
47       * @param classLoader
48       *            the class loader to use when generating the proxy2
49       * @param delegateProvider
50       *            the delegate provider
51       * @param proxyClasses
52       *            the interfaces that the proxy2 should implement
53       * @return a proxy2 which delegates to the object provided by the target <code>delegateProvider>
54       */
55      @Override
56      public <T> T createDelegatorProxy(ClassLoader classLoader, ObjectProvider<?> delegateProvider,
57              Class<?>... proxyClasses)
58      {
59          @SuppressWarnings("unchecked") // type inference
60          final T result = (T) Proxy.newProxyInstance(classLoader, proxyClasses, new DelegatorInvocationHandler(
61                  delegateProvider));
62          return result;
63      }
64  
65      /**
66       * Creates a proxy2 which passes through a {@link Interceptor interceptor} before eventually reaching the
67       * <code>target</code> object.
68       * 
69       * @param classLoader
70       *            the class loader to use when generating the proxy2
71       * @param target
72       *            the target object
73       * @param interceptor
74       *            the method interceptor
75       * @param proxyClasses
76       *            the interfaces that the proxy2 should implement.
77       * @return a proxy2 which passes through a {@link Interceptor interceptor} before eventually reaching the
78       *         <code>target</code> object.
79       */
80      @Override
81      public <T> T createInterceptorProxy(ClassLoader classLoader, Object target, Interceptor interceptor,
82              Class<?>... proxyClasses)
83      {
84          @SuppressWarnings("unchecked") // type inference
85          final T result = (T) Proxy.newProxyInstance(classLoader, proxyClasses, new InterceptorInvocationHandler(target,
86                  interceptor));
87          return result;
88      }
89  
90      /**
91       * Creates a proxy2 which uses the provided {@link Invoker} to handle all method invocations.
92       * 
93       * @param classLoader
94       *            the class loader to use when generating the proxy2
95       * @param invoker
96       *            the invoker
97       * @param proxyClasses
98       *            the interfaces that the proxy2 should implement
99       * @return a proxy2 which uses the provided {@link Invoker} to handle all method invocations
100      */
101     @Override
102     public <T> T createInvokerProxy(ClassLoader classLoader, Invoker invoker, Class<?>... proxyClasses)
103     {
104         @SuppressWarnings("unchecked") // type inference
105         final T result = (T) Proxy.newProxyInstance(classLoader, proxyClasses, new InvokerInvocationHandler(invoker));
106         return result;
107     }
108 
109     //******************************************************************************************************************
110     // Inner Classes
111     //******************************************************************************************************************
112 
113     private abstract static class AbstractInvocationHandler implements InvocationHandler, Serializable
114     {
115         /** Serialization version */
116         private static final long serialVersionUID = 1L;
117 
118         @Override
119         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
120         {
121             if (ProxyUtils.isHashCode(method))
122             {
123                 return Integer.valueOf(System.identityHashCode(proxy));
124             }
125             else if (ProxyUtils.isEqualsMethod(method))
126             {
127                 return Boolean.valueOf(proxy == args[0]);
128             }
129             else
130             {
131                 return invokeImpl(proxy, method, args);
132             }
133         }
134 
135         protected abstract Object invokeImpl(Object proxy, Method method, Object[] args) throws Throwable;
136     }
137 
138     private static class DelegatorInvocationHandler extends AbstractInvocationHandler
139     {
140         /** Serialization version */
141         private static final long serialVersionUID = 1L;
142 
143         private final ObjectProvider<?> delegateProvider;
144 
145         protected DelegatorInvocationHandler(ObjectProvider<?> delegateProvider)
146         {
147             this.delegateProvider = delegateProvider;
148         }
149 
150         @Override
151         public Object invokeImpl(Object proxy, Method method, Object[] args) throws Throwable
152         {
153             try
154             {
155                 return method.invoke(delegateProvider.getObject(), args);
156             }
157             catch (InvocationTargetException e)
158             {
159                 throw e.getTargetException();
160             }
161         }
162     }
163 
164     private static class InterceptorInvocationHandler extends AbstractInvocationHandler
165     {
166         /** Serialization version */
167         private static final long serialVersionUID = 1L;
168 
169         private final Object target;
170         private final Interceptor methodInterceptor;
171 
172         public InterceptorInvocationHandler(Object target, Interceptor methodInterceptor)
173         {
174             this.target = target;
175             this.methodInterceptor = methodInterceptor;
176         }
177 
178         @Override
179         public Object invokeImpl(Object proxy, Method method, Object[] args) throws Throwable
180         {
181             final ReflectionInvocation invocation = new ReflectionInvocation(proxy, target, method, args);
182             return methodInterceptor.intercept(invocation);
183         }
184     }
185 
186     private static class InvokerInvocationHandler extends AbstractInvocationHandler
187     {
188         /** Serialization version */
189         private static final long serialVersionUID = 1L;
190 
191         private final Invoker invoker;
192 
193         public InvokerInvocationHandler(Invoker invoker)
194         {
195             this.invoker = invoker;
196         }
197 
198         @Override
199         public Object invokeImpl(Object proxy, Method method, Object[] args) throws Throwable
200         {
201             return invoker.invoke(proxy, method, args);
202         }
203     }
204 
205     private static class ReflectionInvocation implements Invocation
206     {
207         private final Object proxy;
208         private final Object target;
209         private final Method method;
210         private final Object[] arguments;
211 
212         public ReflectionInvocation(Object proxy, Object target, Method method, Object[] arguments)
213         {
214             this.proxy = proxy;
215             this.target = target;
216             this.method = method;
217             this.arguments = ObjectUtils.defaultIfNull(ArrayUtils.clone(arguments), ProxyUtils.EMPTY_ARGUMENTS);
218         }
219 
220         @Override
221         public Object[] getArguments()
222         {
223             return arguments;
224         }
225 
226         @Override
227         public Method getMethod()
228         {
229             return method;
230         }
231 
232         @Override
233         public Object getProxy()
234         {
235             return proxy;
236         }
237 
238         @Override
239         public Object proceed() throws Throwable
240         {
241             try
242             {
243                 return method.invoke(target, arguments);
244             }
245             catch (InvocationTargetException e)
246             {
247                 throw e.getTargetException();
248             }
249         }
250     }
251 }