org.jboss.arquillian.graphene.proxy.GrapheneProxy Maven / Gradle / Ivy
/**
* JBoss, Home of Professional Open Source
* Copyright 2013, Red Hat, Inc. and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.arquillian.graphene.proxy;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import net.sf.cglib.proxy.Enhancer;
import org.jboss.arquillian.graphene.context.GrapheneContext;
/**
* GrapheneProxy provides methods for wrapping the target of invocation in the proxy.
*
* @author Lukas Fryc
*/
public final class GrapheneProxy {
/**
* Returns whether given object
is instance of context proxy.
*
* @param target target instance to check
* @return true when target is a Proxy instance, false otherwise
*/
public static boolean isProxyInstance(Object target) {
return target instanceof GrapheneProxyInstance;
}
/**
*
* Wraps the given target instance in the proxy.
*
*
*
* The list of interfaces which should be implemented by the proxy is automatically computer from provided instance.
*
*
*
* @param target the target instance to be wrapped
* @return the proxy wrapping the target
*/
@SuppressWarnings("unchecked")
public static T getProxyForTarget(GrapheneContext context, T target) {
if (Modifier.isFinal(target.getClass().getModifiers())) {
if (target.getClass().getInterfaces().length > 0) {
return GrapheneProxy.getProxyForTargetWithInterfaces(context, target, target.getClass().getInterfaces());
} else {
throw new IllegalStateException("Can't create a proxy for " + target.getClass()
+ ", it's final and id doesn't implement any interface.");
}
}
GrapheneProxyHandler handler = GrapheneContextualHandler.forTarget(context, target);
return (T) createProxy(handler, target.getClass());
}
/**
*
* Wraps the given target instance in the proxy.
*
*
*
* The list of interfaces which should be implemented by the proxy needs to be provided.
*
*
*
* @param target the target instance to be wrapped
* @param interfaces the list of interfaces which should be implemented by created proxy
* @return the proxy wrapping the target
*/
@SuppressWarnings("unchecked")
public static T getProxyForTargetWithInterfaces(GrapheneContext context, T target, Class>... interfaces) {
GrapheneProxyHandler handler = GrapheneContextualHandler.forTarget(context, target);
return (T) createProxy(handler, null, interfaces);
}
/**
*
* Wraps the given future target instance in the proxy.
*
*
*
* Future target can be computed dynamically for each invocation of proxy.
*
*
*
* In this case interfaces which should the proxy implement needs to be provided.
*
*
*
* The list of any classes can be provided, the list of interfaces will be automatically computed.
*
*
* @param futureTarget the future target of invocation
* @param baseType the list of classes from which should be determined what interfaces will returned proxy implement
* @param additionalInterfaces additional interfaces which should a created proxy implement
* @return the proxy wrapping the future target
*/
public static T getProxyForFutureTarget(GrapheneContext context, FutureTarget futureTarget, Class> baseType, Class>... additionalInterfaces) {
if (baseType != null && !baseType.isInterface() && Modifier.isFinal(baseType.getModifiers())) {
if (additionalInterfaces.length > 0) {
return GrapheneProxy.getProxyForFutureTarget(context, futureTarget, additionalInterfaces[0], additionalInterfaces);
} else {
throw new IllegalStateException("Can't create a proxy for " + baseType
+ ", it's final and no additional interface has been given.");
}
}
GrapheneProxyHandler handler = GrapheneContextualHandler.forFuture(context, futureTarget);
return getProxyForHandler(handler, baseType, additionalInterfaces);
}
@SuppressWarnings("unchecked")
public static T getProxyForHandler(GrapheneProxyHandler handler, Class> baseType, Class>... additionalInterfaces) {
return (T) createProxy(handler, baseType, additionalInterfaces);
}
/**
*
* Uses given proxy factory to create new proxy for given implementation class or interfaces with the given method handler.
*
*
*
* The returned proxy implements {@link GrapheneProxyInstance} by default.
*
* @param factory the {@link ProxyFactory} which will be used to create proxy
* @param interceptor the {@link MethodHandler} for handling invocation
* @param baseType the class or interface used as base type or null if additionalInterfaces list should be used instead
* @param additionalInterfaces additional interfaces which should a created proxy implement
* @return the proxy for given implementation class or interfaces with the given method handler.
*/
@SuppressWarnings("unchecked")
static T createProxy(GrapheneProxyHandler interceptor, Class baseType, Class>... additionalInterfaces) {
if (baseType != null) {
while (Enhancer.isEnhanced(baseType)) {
baseType = (Class) baseType.getSuperclass();
}
}
Class>[] ancillaryTypes = GrapheneProxyUtil.concatClasses(additionalInterfaces, GrapheneProxyInstance.class);
T result;
if (baseType == null || baseType.isInterface()) {
if (baseType != null) {
ancillaryTypes = GrapheneProxyUtil.concatClasses(ancillaryTypes, baseType);
}
result = (T) Proxy.newProxyInstance(GrapheneProxy.class.getClassLoader(), ancillaryTypes, interceptor);
} else {
result = (T) ClassImposterizer.INSTANCE.imposterise(interceptor, baseType, ancillaryTypes);
}
return result;
}
/**
* Interface for computation of future target of invocation by proxy.
*/
public interface FutureTarget {
Object getTarget();
}
public static class ConstantFutureTarget implements FutureTarget {
private final Object target;
public ConstantFutureTarget(Object target) {
this.target = target;
}
@Override
public Object getTarget() {
return target;
}
}
}