/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.core.registry;
import static org.reflections.ReflectionUtils.getAllFields;
import static org.reflections.ReflectionUtils.withAnnotation;
import org.mule.runtime.api.exception.MuleException;
import org.mule.runtime.api.lifecycle.InitialisationException;
import org.mule.runtime.core.api.Injector;
import org.mule.runtime.core.api.MuleContext;
import org.mule.runtime.core.api.registry.LifecycleRegistry;
import org.mule.runtime.core.api.registry.RegistrationException;
import org.mule.runtime.core.internal.lifecycle.phases.NotInLifecyclePhase;
import java.lang.reflect.Field;
import javax.inject.Inject;
/**
* A very simple implementation of {@link LifecycleRegistry}. Useful for starting really lightweight contexts which don't depend
* on heavier object containers such as Spring or Guice (testing being the best example).
* <p/>
* The {@link #inject(Object)} operation will only consider fields annotated with {@link Inject} and will perform the injection
* using simple, not-cached reflection. Also, initialisation lifecycle will be performed in pseudo-random order, no analysis will
* be done to ensure that dependencies of a given object get their lifecycle before it.
*
* @since 3.7.0
*/
public class SimpleRegistry extends TransientRegistry implements LifecycleRegistry, Injector {
private static final String REGISTRY_ID = "org.mule.runtime.core.Registry.Simple";
public SimpleRegistry(MuleContext muleContext) {
super(REGISTRY_ID, muleContext);
}
@Override
protected void doInitialise() throws InitialisationException {
injectFieldDependencies();
super.doInitialise();
}
/**
* This implementation doesn't support applying lifecycle upon lookup and thus this method simply delegates into
* {@link #lookupObject(String)}
*/
@Override
public <T> T lookupObject(String key, boolean applyLifecycle) {
return lookupObject(key);
}
/**
* {@inheritDoc}
*/
@Override
protected void doRegisterObject(String key, Object object, Object metadata) throws RegistrationException {
Object previous = doGet(key);
if (previous != null) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("An entry already exists for key %s. It will be replaced", key));
}
unregisterObject(key);
}
doPut(key, object);
try {
getLifecycleManager().applyCompletedPhases(object);
} catch (MuleException e) {
throw new RegistrationException(e);
}
}
/**
* {@inheritDoc}
*/
@Override
public Object applyLifecycle(Object object) throws MuleException {
getLifecycleManager().applyCompletedPhases(object);
return object;
}
/**
* {@inheritDoc}
*/
@Override
public Object applyLifecycle(Object object, String phase) throws MuleException {
if (phase == null) {
getLifecycleManager().applyCompletedPhases(object);
} else {
getLifecycleManager().applyPhase(object, NotInLifecyclePhase.PHASE_NAME, phase);
}
return object;
}
/**
* {@inheritDoc}
*/
@Override
public void applyLifecycle(Object object, String startPhase, String toPhase) throws MuleException {
getLifecycleManager().applyPhase(object, startPhase, toPhase);
}
/**
* {@inheritDoc}
*/
@Override
public <T> T inject(T object) {
return (T) applyProcessors(object, null);
}
/**
* {@inheritDoc}
*/
@Override
protected Object applyProcessors(Object object, Object metadata) {
return injectInto(super.applyProcessors(object, metadata));
}
private void injectFieldDependencies() throws InitialisationException {
lookupObjects(Object.class).forEach(this::injectInto);
}
private <T> T injectInto(T object) {
for (Field field : getAllFields(object.getClass(), withAnnotation(Inject.class))) {
Class<?> dependencyType = field.getType();
try {
field.setAccessible(true);
Object dependency = lookupObject(dependencyType);
if (dependency == null && MuleContext.class.isAssignableFrom(dependencyType)) {
dependency = muleContext;
}
if (dependency != null) {
field.set(object, dependency);
}
} catch (Exception e) {
throw new RuntimeException(String.format("Could not inject dependency on field %s of type %s", field.getName(),
object.getClass().getName()),
e);
}
}
return object;
}
}