blob: 8e99ee30a303cb56b5da24502fa899837c04f430 [file] [log] [blame]
/*
* 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.proxy2.jdk;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.proxy2.Interceptor;
import org.apache.commons.proxy2.Invocation;
import org.apache.commons.proxy2.Invoker;
import org.apache.commons.proxy2.ObjectProvider;
import org.apache.commons.proxy2.ProxyUtils;
import org.apache.commons.proxy2.impl.AbstractProxyFactory;
/**
* {@link org.apache.commons.proxy2.ProxyFactory ProxyFactory} implementation that uses {@link java.lang.reflect.Proxy}
* proxies.
*/
public class JdkProxyFactory extends AbstractProxyFactory
{
//******************************************************************************************************************
// ProxyFactory Implementation
//******************************************************************************************************************
/**
* Creates a proxy2 which delegates to the object provided by <code>delegateProvider</code>.
*
* @param classLoader
* the class loader to use when generating the proxy2
* @param delegateProvider
* the delegate provider
* @param proxyClasses
* the interfaces that the proxy2 should implement
* @return a proxy2 which delegates to the object provided by the target <code>delegateProvider>
*/
@Override
public <T> T createDelegatorProxy(ClassLoader classLoader, ObjectProvider<?> delegateProvider,
Class<?>... proxyClasses)
{
@SuppressWarnings("unchecked") // type inference
final T result = (T) Proxy.newProxyInstance(classLoader, proxyClasses, new DelegatorInvocationHandler(
delegateProvider));
return result;
}
/**
* Creates a proxy2 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 proxy2
* @param target
* the target object
* @param interceptor
* the method interceptor
* @param proxyClasses
* the interfaces that the proxy2 should implement.
* @return a proxy2 which passes through a {@link Interceptor interceptor} before eventually reaching the
* <code>target</code> object.
*/
@Override
public <T> T createInterceptorProxy(ClassLoader classLoader, Object target, Interceptor interceptor,
Class<?>... proxyClasses)
{
@SuppressWarnings("unchecked") // type inference
final T result = (T) Proxy.newProxyInstance(classLoader, proxyClasses, new InterceptorInvocationHandler(target,
interceptor));
return result;
}
/**
* Creates a proxy2 which uses the provided {@link Invoker} to handle all method invocations.
*
* @param classLoader
* the class loader to use when generating the proxy2
* @param invoker
* the invoker
* @param proxyClasses
* the interfaces that the proxy2 should implement
* @return a proxy2 which uses the provided {@link Invoker} to handle all method invocations
*/
@Override
public <T> T createInvokerProxy(ClassLoader classLoader, Invoker invoker, Class<?>... proxyClasses)
{
@SuppressWarnings("unchecked") // type inference
final T result = (T) Proxy.newProxyInstance(classLoader, proxyClasses, new InvokerInvocationHandler(invoker));
return result;
}
//******************************************************************************************************************
// Inner Classes
//******************************************************************************************************************
private abstract static class AbstractInvocationHandler implements InvocationHandler, Serializable
{
/** Serialization version */
private static final long serialVersionUID = 1L;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
if (ProxyUtils.isHashCode(method))
{
return Integer.valueOf(System.identityHashCode(proxy));
}
else if (ProxyUtils.isEqualsMethod(method))
{
return Boolean.valueOf(proxy == args[0]);
}
else
{
return invokeImpl(proxy, method, args);
}
}
protected abstract Object invokeImpl(Object proxy, Method method, Object[] args) throws Throwable;
}
private static class DelegatorInvocationHandler extends AbstractInvocationHandler
{
/** Serialization version */
private static final long serialVersionUID = 1L;
private final ObjectProvider<?> delegateProvider;
protected DelegatorInvocationHandler(ObjectProvider<?> delegateProvider)
{
this.delegateProvider = delegateProvider;
}
@Override
public Object invokeImpl(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 extends AbstractInvocationHandler
{
/** Serialization version */
private static final long serialVersionUID = 1L;
private final Object target;
private final Interceptor methodInterceptor;
public InterceptorInvocationHandler(Object target, Interceptor methodInterceptor)
{
this.target = target;
this.methodInterceptor = methodInterceptor;
}
@Override
public Object invokeImpl(Object proxy, Method method, Object[] args) throws Throwable
{
final ReflectionInvocation invocation = new ReflectionInvocation(proxy, target, method, args);
return methodInterceptor.intercept(invocation);
}
}
private static class InvokerInvocationHandler extends AbstractInvocationHandler
{
/** Serialization version */
private static final long serialVersionUID = 1L;
private final Invoker invoker;
public InvokerInvocationHandler(Invoker invoker)
{
this.invoker = invoker;
}
@Override
public Object invokeImpl(Object proxy, Method method, Object[] args) throws Throwable
{
return invoker.invoke(proxy, method, args);
}
}
private static class ReflectionInvocation implements Invocation
{
private final Object proxy;
private final Object target;
private final Method method;
private final Object[] arguments;
public ReflectionInvocation(Object proxy, Object target, Method method, Object[] arguments)
{
this.proxy = proxy;
this.target = target;
this.method = method;
this.arguments = ObjectUtils.defaultIfNull(ArrayUtils.clone(arguments), ProxyUtils.EMPTY_ARGUMENTS);
}
@Override
public Object[] getArguments()
{
return arguments;
}
@Override
public Method getMethod()
{
return method;
}
@Override
public Object getProxy()
{
return proxy;
}
@Override
public Object proceed() throws Throwable
{
try
{
return method.invoke(target, arguments);
}
catch (InvocationTargetException e)
{
throw e.getTargetException();
}
}
}
}