package de.hilling.junit.cdi.scope;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.annotation.Priority;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import org.apache.deltaspike.core.api.provider.BeanProvider;
import de.hilling.junit.cdi.CurrentTestInformation;
import de.hilling.junit.cdi.annotations.BypassMocks;
import de.hilling.junit.cdi.util.ReflectionsUtils;
@Rediractable
@Interceptor
@Dependent
@Priority(0)
public class CallRedirectionInterceptor implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
private Instance<InvocationTargetManager> invocationTargetManager;
@Inject
private Instance<CurrentTestInformation> testInformation;
@AroundInvoke
public Object invokeMockableBean(InvocationContext ctx) throws Throwable {
Class<?> javaClass = ReflectionsUtils.getOriginalClass(ctx.getTarget().getClass());
if (invocationTargetManager.get().isAlternativeEnabled(javaClass)) {
return callAlternative(ctx, javaClass);
} else if (!bypassMocks() && invocationTargetManager.get().isMockEnabled(javaClass)) {
return callMock(ctx, javaClass);
} else {
return ctx.proceed();
}
}
private boolean bypassMocks() {
if (testInformation.isUnsatisfied()) {
throw new RuntimeException("could not find testinformation.");
}
final Method testMethod = testInformation.get().getMethod();
if (testMethod != null) {
return testMethod.isAnnotationPresent(BypassMocks.class);
} else {
return false;
}
}
private Object callAlternative(InvocationContext ctx, Class<?> javaClass) throws Throwable {
try {
Object alternative = BeanProvider
.getContextualReference(invocationTargetManager.get().alternativeFor(javaClass));
Method method = ctx.getMethod();
Method alternativeMethod = alternative.getClass().getMethod(method.getName(), method.getParameterTypes());
return alternativeMethod.invoke(alternative, ctx.getParameters());
} catch (NoSuchMethodException nme) {
return callMock(ctx, javaClass);
} catch (InvocationTargetException ite) {
throw ite.getCause();
}
}
private Object callMock(InvocationContext ctx, Class<?> javaClass) throws Throwable {
try {
return ctx.getMethod().invoke(invocationTargetManager.get().mock(javaClass), ctx.getParameters());
} catch (InvocationTargetException ite) {
throw ite.getCause();
}
}
}