package atg.tools.dynunit.internal.inject; import atg.nucleus.Nucleus; import atg.tools.dynunit.Nuke; import atg.tools.dynunit.inject.NucleusInjector; import atg.tools.dynunit.nucleus.NucleusFactory; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import javax.inject.Inject; import javax.inject.Named; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import static org.apache.commons.lang3.ClassUtils.PACKAGE_SEPARATOR_CHAR; import static org.apache.commons.lang3.ClassUtils.getPackageCanonicalName; import static org.apache.commons.lang3.reflect.FieldUtils.writeField; /** * @author msicker * @version 1.0.0 */ public class NucleusInjectorImpl implements NucleusInjector { private static final Logger logger = LogManager.getLogger(); private Nucleus nucleus; private File configPath; private Object testInstance; private Map<Field, String> injectableFields; @Override public void init(final Object testInstance) { logger.entry(testInstance); this.testInstance = testInstance; findInjectableFields(); try { injectNucleus(); injectComponents(); } catch (IOException e) { logException(e); logger.error("Couldn't create Nucleus using configPath: {}", configPath.getAbsolutePath()); } catch (IllegalAccessException e) { logException(e); logger.error("Can't inject component instance."); } logger.exit(); } private void findInjectableFields() { logger.entry(); final Field[] fields = testInstance.getClass().getDeclaredFields(); injectableFields = new ConcurrentHashMap<Field, String>(fields.length); for (Field field : fields) { if (isFieldInjectable(field)) { logger.debug("Found injectable field: {}", field.getName()); addInjectableField(field); } } logger.exit(); } private boolean isFieldInjectable(final Field field) { logger.entry(field); return logger.exit(field.isAnnotationPresent(Inject.class)); } private void addInjectableField(final Field field) { logger.entry(field); injectableFields.put(field, getFieldComponentName(field)); logger.exit(); } private void removeInjectableField(final Field field) { logger.entry(field); injectableFields.remove(field); logger.exit(); } private String getFieldComponentName(final Field field) { logger.entry(field); final Named componentName = field.getAnnotation(Named.class); if (componentName == null) { return logger.exit(generateDefaultComponentName(field)); } else { return logger.exit(componentName.value()); } } private String generateDefaultComponentName(final Field field) { logger.entry(field); final String packageCanonicalName = getPackageCanonicalName(field.getDeclaringClass()); return logger.exit("/" + packageCanonicalName.replace(PACKAGE_SEPARATOR_CHAR, '/')); } private void injectNucleus() throws IOException, IllegalAccessException { logger.entry(); for (final Field field : injectableFields.keySet()) { final Nuke payload = nuke(field); if (payload != null) { initializeConfigPath(payload.value()); initializeNucleus(); injectNucleusIntoField(field); removeInjectableField(field); } } logger.exit(); } private Nuke nuke(final Field field) { logger.entry(field); return logger.exit(field.getAnnotation(Nuke.class)); } private void initializeConfigPath(final String configPath) { logger.entry(configPath); this.configPath = new File(configPath); logger.exit(); } private void initializeNucleus() throws IOException { logger.entry(); nucleus = NucleusFactory.getFactory().createNucleus(configPath); logger.exit(); } private void injectNucleusIntoField(final Field field) throws IllegalAccessException { logger.entry(field); writeField(field, testInstance, nucleus, true); logger.exit(); } private void injectComponents() throws IllegalAccessException { logger.entry(); for (final Map.Entry<Field, String> entry : injectableFields.entrySet()) { writeField(entry.getKey(), testInstance, resolveName(entry.getValue()), true); } logger.exit(); } private Object resolveName(final String componentName) { logger.entry(componentName); return logger.exit(nucleus.resolveName(componentName)); } private void logException(final Throwable exception) { logger.entry(exception); logger.catching(Level.ERROR, exception); logger.exit(); } }