nl.hsac.fitnesse.slim.interaction.FixtureFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hsac-fitnesse-fixtures Show documentation
Show all versions of hsac-fitnesse-fixtures Show documentation
Fixtures to assist in testing via FitNesse
package nl.hsac.fitnesse.slim.interaction;
import fitnesse.slim.fixtureInteraction.DefaultInteraction;
import fitnesse.slim.fixtureInteraction.FixtureInteraction;
import fitnesse.slim.fixtureInteraction.InteractionAwareFixture;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
/**
* Factory to create fixture instances that behave like the way they do when Slim invokes them.
* This means #aroundSlimInvoke() is applied around their normal methods, so that they can be used by
* 'normal' Java classes and not just the wiki.
* It is not exactly the same as Slim does, as instance created by this factory do not have #aroundSlimInvoke() applied
* to calls to 'final' methods. This is a limitation of the technology used.
*/
public class FixtureFactory {
private static final Map, Factory> FACTORIES = new HashMap, Factory>();
private FixtureInteraction interaction = null;
/**
* @return interaction that will be passed to #aroundSlimInvoke().
*/
public FixtureInteraction getInteraction() {
if (interaction == null) {
interaction = new DefaultInteraction();
}
return interaction;
}
/**
* @param interaction interaction to pass to #aroundSlimInvoke().
*/
public void setInteraction(FixtureInteraction interaction) {
this.interaction = interaction;
}
/**
* Creates new instance of fixture.
* @param clazz class to instantiate.
* @param type to create.
* @return instance of clazz (subclass, actually) that will have #aroundSlimInvoke() invoked on each method call.
*/
public T create(Class clazz) {
return create(clazz, null, null);
}
/**
* Creates new instance of fixture.
* @param clazz class to instantiate.
* @param constructorArg argument to pass to constructor of clazz.
* @param type to create.
* @return instance of clazz (subclass, actually) that will have #aroundSlimInvoke() invoked on each method call.
*/
public T create(Class clazz, int constructorArg) {
return create(clazz, new Class>[] {int.class}, new Object[] {constructorArg});
}
/**
* Creates new instance of fixture.
* @param clazz class to instantiate.
* @param constructorArg argument to pass to constructor of clazz.
* @param type to create.
* @return instance of clazz (subclass, actually) that will have #aroundSlimInvoke() invoked on each method call.
*/
public T create(Class clazz, long constructorArg) {
return create(clazz, new Class>[] {long.class}, new Object[] {constructorArg});
}
/**
* Creates new instance of fixture.
* @param clazz class to instantiate.
* @param constructorArg argument to pass to constructor of clazz.
* @param type to create.
* @return instance of clazz (subclass, actually) that will have #aroundSlimInvoke() invoked on each method call.
*/
public T create(Class clazz, double constructorArg) {
return create(clazz, new Class>[] {double.class}, new Object[] {constructorArg});
}
/**
* Creates new instance of fixture.
* @param clazz class to instantiate.
* @param constructorArg argument to pass to constructor of clazz.
* @param type to create.
* @return instance of clazz (subclass, actually) that will have #aroundSlimInvoke() invoked on each method call.
*/
public T create(Class clazz, boolean constructorArg) {
return create(clazz, new Class>[] {boolean.class}, new Object[] {constructorArg});
}
/**
* Creates new instance of fixture.
* @param clazz class to instantiate.
* @param constructorArgs arguments to pass to constructor of clazz.
* @param type to create.
* @return instance of clazz (subclass, actually) that will have #aroundSlimInvoke() invoked on each method call.
*/
public T create(Class clazz, Object... constructorArgs) {
T result;
if (constructorArgs != null && constructorArgs.length > 0) {
Class>[] types = new Class[constructorArgs.length];
for (int i = 0; i < constructorArgs.length; i++) {
types[i] = constructorArgs[i].getClass();
}
result = create(clazz, types, constructorArgs);
} else {
result = create(clazz, null, null);
}
return result;
}
/**
* Creates new instance of fixture.
* @param clazz class to instantiate.
* @param constructorTypes types of arguments used to determine which constructor to use.
* @param constructorArgs arguments to pass to constructor of clazz.
* @param type to create.
* @return instance of clazz (subclass, actually) that will have #aroundSlimInvoke() invoked on each method call.
*/
public T create(Class clazz, Class>[] constructorTypes, Object[] constructorArgs) {
MethodInterceptor callback = createCallback();
T result;
if (FACTORIES.containsKey(clazz)) {
Factory factory = FACTORIES.get(clazz);
result = createUsingFactory(callback, factory, constructorTypes, constructorArgs);
} else {
result = createFirst(callback, clazz, constructorTypes, constructorArgs);
FACTORIES.put(clazz, (Factory) result);
}
return result;
}
protected T createUsingFactory(Callback callback, Factory factory, Class>[] constructorTypes, Object[] constructorArgs) {
Callback[] callbacks = new Callback[] { callback };
T result;
if (constructorArgs != null && constructorArgs.length > 0) {
result = (T) factory.newInstance(constructorTypes, constructorArgs, callbacks);
} else {
result = (T) factory.newInstance(callbacks);
}
return result;
}
protected T createFirst(Callback callback, Class clazz, Class>[] constructorTypes, Object[] constructorArgs) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(callback);
T result;
if (constructorArgs != null && constructorArgs.length > 0) {
result = (T) enhancer.create(constructorTypes, constructorArgs);
} else {
result = (T) enhancer.create();
}
return result;
}
protected MethodInterceptor createCallback() {
FixtureInteraction nestedInteraction = getInteraction();
return new LikeSlimInteraction(nestedInteraction);
}
protected static class LikeSlimInteraction implements MethodInterceptor {
private final FixtureInteraction interaction;
private boolean aroundInvoked = false;
public LikeSlimInteraction(FixtureInteraction fixtureInteraction) {
interaction = fixtureInteraction;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (!aroundInvoked
&& Modifier.isPublic(method.getModifiers())
&& !method.getDeclaringClass().equals(Object.class)
&& !"aroundSlimInvoke".equals(method.getName())) {
aroundInvoked = true;
try {
return ((InteractionAwareFixture) obj).aroundSlimInvoke(interaction, method, args);
} finally {
aroundInvoked = false;
}
} else {
return proxy.invokeSuper(obj, args);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy