package cucumber.runtime.java.needle;
import cucumber.api.java.ObjectFactory;
import cucumber.runtime.java.needle.config.CollectInjectionProvidersFromStepsInstance;
import cucumber.runtime.java.needle.config.CreateInstanceByDefaultConstructor;
import cucumber.runtime.java.needle.config.CucumberNeedleConfiguration;
import de.akquinet.jbosscc.needle.NeedleTestcase;
import de.akquinet.jbosscc.needle.injection.InjectionProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.LinkedHashMap;
import java.util.Map;
import static cucumber.runtime.java.needle.config.CucumberNeedleConfiguration.RESOURCE_CUCUMBER_NEEDLE;
import static java.lang.String.format;
/**
* Needle factory for object resolution inside of cucumber tests.
*/
public class NeedleFactory extends NeedleTestcase implements ObjectFactory {
private final Map<Class<?>, Object> cachedStepsInstances = new LinkedHashMap<Class<?>, Object>();
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final CreateInstanceByDefaultConstructor createInstanceByDefaultConstructor = CreateInstanceByDefaultConstructor.INSTANCE;
private final CollectInjectionProvidersFromStepsInstance collectInjectionProvidersFromStepsInstance = CollectInjectionProvidersFromStepsInstance.INSTANCE;
public NeedleFactory() {
super(setUpInjectionProviders(RESOURCE_CUCUMBER_NEEDLE));
}
@Override
public <T> T getInstance(final Class<T> type) {
logger.trace("getInstance: " + type.getCanonicalName());
assertTypeHasBeenAdded(type);
return nullSafeGetInstance(type);
}
@Override
public void start() {
logger.trace("start()");
for (final Class<?> stepDefinitionType : cachedStepsInstances.keySet()) {
cachedStepsInstances.put(stepDefinitionType, createStepsInstance(stepDefinitionType));
}
}
@Override
public void stop() {
logger.trace("stop()");
for (final Class<?> stepDefinitionType : cachedStepsInstances.keySet()) {
cachedStepsInstances.put(stepDefinitionType, null);
}
}
@Override
public boolean addClass(final Class<?> type) {
logger.trace("addClass(): " + type.getCanonicalName());
// build up cache keys ...
if (!cachedStepsInstances.containsKey(type)) {
cachedStepsInstances.put(type, null);
}
return true;
}
private void assertTypeHasBeenAdded(final Class<?> type) {
if (!cachedStepsInstances.containsKey(type)) {
throw new IllegalStateException(format("%s was not added during addClass()", type.getSimpleName()));
}
}
@SuppressWarnings("unchecked")
private <T> T nullSafeGetInstance(final Class<T> type) {
final Object instance = cachedStepsInstances.get(type);
if (instance == null) {
throw new IllegalStateException(format("instance of type %s has not been initialized in start()!",
type.getSimpleName()));
}
return (T) instance;
}
private <T> T createStepsInstance(final Class<T> type) {
logger.trace("createInstance(): " + type.getCanonicalName());
try {
final T stepsInstance = createInstanceByDefaultConstructor.apply(type);
addInjectionProvider(collectInjectionProvidersFromStepsInstance.apply(stepsInstance));
initTestcase(stepsInstance);
return stepsInstance;
} catch (final Exception e) {
throw new IllegalStateException(e);
}
}
static InjectionProvider<?>[] setUpInjectionProviders(final String resourceName) {
return new CucumberNeedleConfiguration(resourceName).getInjectionProviders();
}
}