001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.proxy2.jdk; 019 020import java.io.Serializable; 021import java.lang.reflect.InvocationHandler; 022import java.lang.reflect.InvocationTargetException; 023import java.lang.reflect.Method; 024import java.lang.reflect.Proxy; 025 026import org.apache.commons.lang3.ArrayUtils; 027import org.apache.commons.lang3.ObjectUtils; 028import org.apache.commons.proxy2.Interceptor; 029import org.apache.commons.proxy2.Invocation; 030import org.apache.commons.proxy2.Invoker; 031import org.apache.commons.proxy2.ObjectProvider; 032import org.apache.commons.proxy2.ProxyUtils; 033import org.apache.commons.proxy2.impl.AbstractProxyFactory; 034 035/** 036 * {@link org.apache.commons.proxy2.ProxyFactory ProxyFactory} implementation that uses {@link java.lang.reflect.Proxy} proxies. 037 */ 038public class JdkProxyFactory extends AbstractProxyFactory 039{ 040 //****************************************************************************************************************** 041 // ProxyFactory Implementation 042 //****************************************************************************************************************** 043 044 /** 045 * Creates a proxy2 which delegates to the object provided by <code>delegateProvider</code>. 046 * 047 * @param classLoader 048 * the class loader to use when generating the proxy2 049 * @param delegateProvider 050 * the delegate provider 051 * @param proxyClasses 052 * the interfaces that the proxy2 should implement 053 * @return a proxy2 which delegates to the object provided by the target <code>delegateProvider> 054 */ 055 @Override 056 public <T> T createDelegatorProxy(ClassLoader classLoader, ObjectProvider<?> delegateProvider, 057 Class<?>... proxyClasses) 058 { 059 @SuppressWarnings("unchecked") // type inference 060 final T result = (T) Proxy.newProxyInstance(classLoader, proxyClasses, new DelegatorInvocationHandler( 061 delegateProvider)); 062 return result; 063 } 064 065 /** 066 * Creates a proxy2 which passes through a {@link Interceptor interceptor} before eventually reaching the 067 * <code>target</code> object. 068 * 069 * @param classLoader 070 * the class loader to use when generating the proxy2 071 * @param target 072 * the target object 073 * @param interceptor 074 * the method interceptor 075 * @param proxyClasses 076 * the interfaces that the proxy2 should implement. 077 * @return a proxy2 which passes through a {@link Interceptor interceptor} before eventually reaching the 078 * <code>target</code> object. 079 */ 080 @Override 081 public <T> T createInterceptorProxy(ClassLoader classLoader, Object target, Interceptor interceptor, 082 Class<?>... proxyClasses) 083 { 084 @SuppressWarnings("unchecked") // type inference 085 final T result = (T) Proxy.newProxyInstance(classLoader, proxyClasses, new InterceptorInvocationHandler(target, 086 interceptor)); 087 return result; 088 } 089 090 /** 091 * Creates a proxy2 which uses the provided {@link Invoker} to handle all method invocations. 092 * 093 * @param classLoader 094 * the class loader to use when generating the proxy2 095 * @param invoker 096 * the invoker 097 * @param proxyClasses 098 * the interfaces that the proxy2 should implement 099 * @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}