IronJacamar.java
/*
* IronJacamar, a Java EE Connector Architecture implementation
* Copyright 2015, Red Hat Inc, and individual contributors
* as indicated by the @author tags. See the copyright.txt file 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 Eclipse Public License 1.0 as
* published by the Free Software Foundation.
*
* 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 Eclipse
* Public License for more details.
*
* You should have received a copy of the Eclipse 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.ironjacamar.embedded.junit4;
import org.ironjacamar.embedded.Configuration;
import org.ironjacamar.embedded.Deployment;
import org.ironjacamar.embedded.Embedded;
import org.ironjacamar.embedded.EmbeddedFactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.annotation.Resource;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.jboss.shrinkwrap.api.spec.ResourceAdapterArchive;
import org.jboss.shrinkwrap.descriptor.api.Descriptor;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkField;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import org.junit.runners.model.TestClass;
/**
* IronJacamar JUnit 4 runner
*/
public class IronJacamar extends BlockJUnit4ClassRunner
{
/** Embedded instance */
private Embedded embedded;
/** Static deployments */
private List<Object> staticDeployments;
/** Deployments */
private List<Object> deployments;
/**
* Constructor
* @param clz The class
* @exception InitializationError If the test can't be initiazed
*/
public IronJacamar(Class<?> clz) throws InitializationError
{
super(clz);
this.embedded = null;
this.staticDeployments = new ArrayList<>();
this.deployments = new ArrayList<>();
}
/**
* {@inheritDoc}
*/
@Override
protected Statement withBefores(final FrameworkMethod method, final Object target, final Statement statement)
{
final Statement befores = super.withBefores(method, target, new NoopStatement());
return new Statement()
{
@Override
public void evaluate() throws Throwable
{
TestClass tc = getTestClass();
// Non-static @Deployment
List<FrameworkMethod> fms = tc.getAnnotatedMethods(Deployment.class);
if (fms != null && !fms.isEmpty())
{
Collection<FrameworkMethod> filtered = filterAndSort(fms, false);
for (FrameworkMethod fm : filtered)
{
SecurityActions.setAccessible(fm.getMethod());
Class<?> returnType = fm.getReturnType();
if (URL.class.isAssignableFrom(returnType))
{
Object[] parameters = getParameters(fm);
URL result = (URL)fm.invokeExplosively(target, parameters);
embedded.deploy(result);
deployments.add(result);
}
else if (ResourceAdapterArchive.class.isAssignableFrom(returnType))
{
Object[] parameters = getParameters(fm);
ResourceAdapterArchive result = (ResourceAdapterArchive)fm.invokeExplosively(target, parameters);
embedded.deploy(result);
deployments.add(result);
}
else if (Descriptor.class.isAssignableFrom(returnType))
{
Object[] parameters = getParameters(fm);
Descriptor result = (Descriptor)fm.invokeExplosively(target, parameters);
embedded.deploy(result);
deployments.add(result);
}
else
{
throw new Exception("Unsupported deployment type: " + returnType.getName());
}
}
}
// Non-static @Inject / @Named
List<FrameworkField> fields = tc.getAnnotatedFields(javax.inject.Inject.class);
if (fields != null && !fields.isEmpty())
{
for (FrameworkField f : fields)
{
if (!Modifier.isStatic(f.getField().getModifiers()))
{
SecurityActions.setAccessible(f.getField());
if (Embedded.class.equals(f.getType()))
{
f.getField().set(target, embedded);
}
else
{
javax.inject.Named name = f.getAnnotation(javax.inject.Named.class);
if (name != null && name.value() != null)
{
Object value = embedded.lookup(name.value(), f.getType());
f.getField().set(target, value);
}
else
{
Object value = embedded.lookup(f.getType().getSimpleName(), f.getType());
f.getField().set(target, value);
}
}
}
}
}
// Non-static @Resource
fields = tc.getAnnotatedFields(Resource.class);
if (fields != null && !fields.isEmpty())
{
Context context = createContext();
for (FrameworkField f : fields)
{
SecurityActions.setAccessible(f.getField());
if (!Modifier.isStatic(f.getField().getModifiers()))
{
Resource resource = (Resource)f.getAnnotation(Resource.class);
String name = null;
if (resource.mappedName() != null)
{
name = resource.mappedName();
}
else if (resource.name() != null)
{
name = resource.name();
}
else if (resource.lookup() != null)
{
name = resource.lookup();
}
f.getField().set(target, context.lookup(name));
}
}
context.close();
}
befores.evaluate();
statement.evaluate();
}
};
}
/**
* {@inheritDoc}
*/
@Override
protected Statement withAfters(final FrameworkMethod method, final Object target, final Statement statement)
{
final Statement afters = super.withAfters(method, target, new NoopStatement());
return new Statement()
{
@Override
public void evaluate() throws Throwable
{
statement.evaluate();
afters.evaluate();
TestClass tc = getTestClass();
// Non-static @Resource
List<FrameworkField> fields = tc.getAnnotatedFields(Resource.class);
if (fields != null && !fields.isEmpty())
{
for (FrameworkField f : fields)
{
SecurityActions.setAccessible(f.getField());
if (!Modifier.isStatic(f.getField().getModifiers()) && !f.getField().getDeclaringClass().isPrimitive())
{
f.getField().set(target, null);
}
}
}
// Non-static @Inject / @Named
fields = tc.getAnnotatedFields(javax.inject.Inject.class);
if (fields != null && !fields.isEmpty())
{
for (FrameworkField f : fields)
{
SecurityActions.setAccessible(f.getField());
if (!Modifier.isStatic(f.getField().getModifiers()) && !f.getField().getDeclaringClass().isPrimitive())
{
f.getField().set(target, null);
}
}
}
// Non-static @Deployment
if (!deployments.isEmpty())
{
for (int i = deployments.size() - 1; i >= 0; i--)
{
Object deployment = deployments.get(i);
if (deployment instanceof URL)
{
embedded.undeploy((URL)deployment);
}
else if (deployment instanceof ResourceAdapterArchive)
{
embedded.undeploy((ResourceAdapterArchive)deployment);
}
else if (deployment instanceof Descriptor)
{
embedded.undeploy((Descriptor)deployment);
}
}
}
deployments.clear();
}
};
}
/**
* {@inheritDoc}
*/
@Override
protected Statement withBeforeClasses(final Statement statement)
{
final Statement beforeClasses = super.withBeforeClasses(new NoopStatement());
return new Statement()
{
@Override
public void evaluate() throws Throwable
{
TestClass tc = getTestClass();
boolean fullProfile = true;
Configuration configuration = tc.getAnnotation(Configuration.class);
if (configuration != null)
fullProfile = configuration.full();
extensionStart(tc);
embedded = EmbeddedFactory.create(fullProfile);
embedded.startup();
Initializer initializer = tc.getAnnotation(Initializer.class);
if (initializer != null && initializer.clazz() != null)
{
try
{
Class<? extends Beans> iClz = initializer.clazz();
Beans bC = iClz.newInstance();
bC.execute(new EmbeddedJCAResolver(embedded));
}
catch (Exception e)
{
throw new Exception("Initializer error from: " + initializer.clazz(), e);
}
}
PreCondition preCondition = tc.getAnnotation(PreCondition.class);
if (preCondition != null && preCondition.condition() != null)
{
try
{
Class<? extends Condition> pCClz = preCondition.condition();
Condition pC = pCClz.newInstance();
pC.verify(new EmbeddedJCAResolver(embedded));
}
catch (Exception e)
{
throw new ConditionException("PreCondition error from: " + preCondition.condition(), e);
}
}
// Static @Deployment
List<FrameworkMethod> fms = tc.getAnnotatedMethods(Deployment.class);
if (fms != null && !fms.isEmpty())
{
Collection<FrameworkMethod> filtered = filterAndSort(fms, true);
for (FrameworkMethod fm : filtered)
{
SecurityActions.setAccessible(fm.getMethod());
Class<?> returnType = fm.getReturnType();
if (URL.class.isAssignableFrom(returnType))
{
Object[] parameters = getParameters(fm);
URL result = (URL)fm.invokeExplosively(null, parameters);
embedded.deploy(result);
staticDeployments.add(result);
}
else if (ResourceAdapterArchive.class.isAssignableFrom(returnType))
{
Object[] parameters = getParameters(fm);
ResourceAdapterArchive result = (ResourceAdapterArchive)fm.invokeExplosively(null, parameters);
embedded.deploy(result);
staticDeployments.add(result);
}
else if (Descriptor.class.isAssignableFrom(returnType))
{
Object[] parameters = getParameters(fm);
Descriptor result = (Descriptor)fm.invokeExplosively(null, parameters);
embedded.deploy(result);
staticDeployments.add(result);
}
else
{
throw new Exception("Unsupported deployment type: " + returnType.getName());
}
}
}
// Static @Inject / @Named
List<FrameworkField> fields = tc.getAnnotatedFields(javax.inject.Inject.class);
if (fields != null && !fields.isEmpty())
{
for (FrameworkField f : fields)
{
if (Modifier.isStatic(f.getField().getModifiers()))
{
SecurityActions.setAccessible(f.getField());
if (Embedded.class.equals(f.getType()))
{
f.getField().set(null, embedded);
}
else
{
javax.inject.Named name = f.getAnnotation(javax.inject.Named.class);
if (name != null && name.value() != null)
{
Object value = embedded.lookup(name.value(), f.getType());
f.getField().set(null, value);
}
else
{
Object value = embedded.lookup(f.getType().getSimpleName(), f.getType());
f.getField().set(null, value);
}
}
}
}
}
// Static @Resource
fields = tc.getAnnotatedFields(Resource.class);
if (fields != null && !fields.isEmpty())
{
Context context = createContext();
for (FrameworkField f : fields)
{
SecurityActions.setAccessible(f.getField());
if (Modifier.isStatic(f.getField().getModifiers()))
{
Resource resource = (Resource)f.getAnnotation(Resource.class);
String name = null;
if (resource.mappedName() != null)
{
name = resource.mappedName();
}
else if (resource.name() != null)
{
name = resource.name();
}
else if (resource.lookup() != null)
{
name = resource.lookup();
}
f.getField().set(null, context.lookup(name));
}
}
context.close();
}
beforeClasses.evaluate();
statement.evaluate();
}
};
}
/**
* {@inheritDoc}
*/
@Override
protected Statement withAfterClasses(final Statement statement)
{
final Statement afterClasses = super.withAfterClasses(new NoopStatement());
return new Statement()
{
@Override
public void evaluate() throws Throwable
{
statement.evaluate();
afterClasses.evaluate();
TestClass tc = getTestClass();
// Static @Resource
List<FrameworkField> fields = tc.getAnnotatedFields(Resource.class);
if (fields != null && !fields.isEmpty())
{
for (FrameworkField f : fields)
{
SecurityActions.setAccessible(f.getField());
if (Modifier.isStatic(f.getField().getModifiers()) && !f.getField().getDeclaringClass().isPrimitive())
{
f.getField().set(null, null);
}
}
}
// Static @Inject / @Named
fields = tc.getAnnotatedFields(javax.inject.Inject.class);
if (fields != null && !fields.isEmpty())
{
for (FrameworkField f : fields)
{
SecurityActions.setAccessible(f.getField());
if (Modifier.isStatic(f.getField().getModifiers()) && !f.getField().getDeclaringClass().isPrimitive())
{
f.getField().set(null, null);
}
}
}
// Static @Deployment
if (!staticDeployments.isEmpty())
{
for (int i = staticDeployments.size() - 1; i >= 0; i--)
{
Object deployment = staticDeployments.get(i);
if (deployment instanceof URL)
{
embedded.undeploy((URL)deployment);
}
else if (deployment instanceof ResourceAdapterArchive)
{
embedded.undeploy((ResourceAdapterArchive)deployment);
}
else if (deployment instanceof Descriptor)
{
embedded.undeploy((Descriptor)deployment);
}
}
}
staticDeployments.clear();
PostCondition postCondition = tc.getAnnotation(PostCondition.class);
if (postCondition != null && postCondition.condition() != null)
{
try
{
Class<? extends Condition> pCClz = postCondition.condition();
Condition pC = pCClz.newInstance();
pC.verify(new EmbeddedJCAResolver(embedded));
}
catch (Exception e)
{
throw new ConditionException("PostCondition error from: " + postCondition.condition(), e);
}
}
Finalizer finalizer = tc.getAnnotation(Finalizer.class);
if (finalizer != null && finalizer.clazz() != null)
{
try
{
Class<? extends Beans> fClz = finalizer.clazz();
Beans fC = fClz.newInstance();
fC.execute(new EmbeddedJCAResolver(embedded));
}
catch (Exception e)
{
throw new Exception("Finalizer error from: " + finalizer.clazz(), e);
}
}
embedded.shutdown();
embedded = null;
extensionStop(tc);
}
};
}
/**
* Extension start
* @param tc The test class
* @exception Exception Thrown in case of an error
*/
public void extensionStart(TestClass tc) throws Exception
{
}
/**
* Extension stop
* @param tc The test class
* @exception Exception Thrown in case of an error
*/
public void extensionStop(TestClass tc) throws Exception
{
}
/**
* Filter and sort
* @param fms The FrameworkMethods
* @param isStatic Filter static
* @return The filtered and sorted FrameworkMethods
* @exception Exception If an order definition is incorrect
*/
private Collection<FrameworkMethod> filterAndSort(List<FrameworkMethod> fms, boolean isStatic) throws Exception
{
SortedMap<Integer, FrameworkMethod> m = new TreeMap<>();
for (FrameworkMethod fm : fms)
{
SecurityActions.setAccessible(fm.getMethod());
if (Modifier.isStatic(fm.getMethod().getModifiers()) == isStatic)
{
Deployment deployment = (Deployment)fm.getAnnotation(Deployment.class);
int order = deployment.order();
if (order <= 0 || m.containsKey(Integer.valueOf(order)))
throw new Exception("Incorrect order definition '" + order + "' on " +
fm.getDeclaringClass().getName() + "#" + fm.getName());
m.put(Integer.valueOf(order), fm);
}
}
return m.values();
}
/**
* Get parameter values for a method
* @param fm The FrameworkMethod
* @return The resolved parameters
*/
private Object[] getParameters(FrameworkMethod fm)
{
Method m = fm.getMethod();
SecurityActions.setAccessible(m);
Class<?>[] parameters = m.getParameterTypes();
Annotation[][] parameterAnnotations = m.getParameterAnnotations();
Object[] result = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++)
{
Annotation[] parameterAnnotation = parameterAnnotations[i];
boolean inject = false;
String name = null;
for (int j = 0; j < parameterAnnotation.length; j++)
{
Annotation a = parameterAnnotation[j];
if (javax.inject.Inject.class.equals(a.annotationType()))
{
inject = true;
}
else if (javax.inject.Named.class.equals(a.annotationType()))
{
name = ((javax.inject.Named)a).value();
}
}
if (inject)
{
result[i] = resolveBean(name != null ? name : parameters[i].getSimpleName(), parameters[i]);
}
else
{
result[i] = null;
}
}
return result;
}
/**
* Resolve a bean
* @param name The name
* @param type The type
* @return The value
*/
private Object resolveBean(String name, Class<?> type)
{
try
{
return embedded.lookup(name, type);
}
catch (Throwable t)
{
return null;
}
}
/**
* Create a context
* @return The context
* @exception Exception Thrown if an error occurs
*/
private Context createContext() throws Exception
{
Properties properties = new Properties();
properties.setProperty("java.naming.factory.initial", "org.jnp.interfaces.LocalOnlyContextFactory");
properties.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
return new InitialContext(properties);
}
/**
* Do nothing
*/
private static class NoopStatement extends Statement
{
/**
* {@inheritDoc}
*/
@Override
public void evaluate() throws Throwable
{
}
}
}