package org.testfun.jee.runner.inject;
import org.testfun.jee.runner.EjbWithMockitoRunnerException;
import javax.ejb.Singleton;
import javax.ejb.Stateless;
import java.util.HashMap;
import java.util.Map;
public class EjbInstanceFactory {
private static final EjbInstanceFactory INSTANCE = new EjbInstanceFactory();
public static EjbInstanceFactory getInstance() {
return INSTANCE;
}
private Map<Class, Class> ejbClassByImplementedInterface;
private EjbInstanceFactory() { }
public Object newInstance(Class<?> implementedInterface) {
Class aClass = getEjbClassByImplementedInterface().get(implementedInterface);
if (aClass == null) {
throw new EjbWithMockitoRunnerException("Implementation for interface not found: " + implementedInterface);
}
try {
return aClass.newInstance();
} catch (Exception e) {
throw new EjbWithMockitoRunnerException("Failed to instantiate interface: " + implementedInterface.getName() , e);
}
}
private Map<Class, Class> getEjbClassByImplementedInterface() {
if (ejbClassByImplementedInterface == null) {
ejbClassByImplementedInterface = new HashMap<>();
ClassPathScanner classPathScanner = new ClassPathScanner();
classPathScanner.scan(new ClassPathScanner.Handler() {
@Override
public void classFound(Class<?> aClass) {
if (!aClass.isInterface()) {
// If the class is annotated with @Stateless, register all the implemented interfaces
if (aClass.getAnnotation(Stateless.class) != null) {
for (Class<?> implementedInterface : aClass.getInterfaces()) {
ejbClassByImplementedInterface.put(implementedInterface, aClass);
}
// Also, register the stateless as if it implements itself so the factory will work for SLSB that doesn't implement any interface.
ejbClassByImplementedInterface.put(aClass, aClass);
}
// If the class is annotated with @Singleton then register the singleton as if it implements "itself" -
// this will allow users to get the "implementing class" of the singleton
else if (aClass.getAnnotation(Singleton.class) != null) {
for (Class<?> implementedInterface : aClass.getInterfaces()) {
ejbClassByImplementedInterface.put(implementedInterface, aClass);
}
ejbClassByImplementedInterface.put(aClass, aClass);
}
}
}
});
}
return ejbClassByImplementedInterface;
}
}