package ilarkesto.scope;
import ilarkesto.base.Reflect;
import ilarkesto.core.logging.Log;
import ilarkesto.core.scope.ComponentReflector;
import ilarkesto.core.scope.In;
import ilarkesto.core.scope.Init;
import ilarkesto.core.scope.Out;
import ilarkesto.core.scope.Scope;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectionComponentReflector implements ComponentReflector {
private static final Log log = Log.get(ReflectionComponentReflector.class);
@Override
public void injectComponents(Object component, Scope scope) {
Reflect.processAnnotations(component, new DependencyInjector(scope));
}
@Override
public void callInitializationMethods(Object component) {
Reflect.processAnnotations(component, new Initializer());
}
@Override
public void outjectComponents(Object component, Scope scope) {
Reflect.processAnnotations(component, new DependencyOutjector(scope));
}
class DependencyOutjector implements Reflect.FieldAnnotationHandler {
private Scope scope;
public DependencyOutjector(Scope scope) {
super();
this.scope = scope;
}
@Override
public void handle(Annotation annotation, Field field, Object component) {
if (annotation.annotationType() != Out.class) return;
String outName = field.getName();
Object outComponent;
try {
if (!field.isAccessible()) field.setAccessible(true);
outComponent = field.get(component);
} catch (Throwable ex) {
throw new DependencyOutjectionFailedException(component, outName, ex);
}
if (outComponent == null) return;
log.debug("Outjecting component field:", component.getClass().getSimpleName() + "." + field.getName());
scope.putComponent(outName, outComponent);
}
}
class Initializer implements Reflect.MethodAnnotationHandler {
@Override
public void handle(Annotation annotation, Method method, Object object) {
if (annotation.annotationType() != Init.class) return;
log.debug("Calling initialization method:", object.getClass().getSimpleName() + "." + method.getName()
+ "()");
try {
if (!method.isAccessible()) method.setAccessible(true);
method.invoke(object);
} catch (Throwable ex) {
throw new InitializationFaildException(object, method.getName(), ex);
}
}
}
class DependencyInjector implements Reflect.FieldAnnotationHandler {
private Scope scope;
public DependencyInjector(Scope scope) {
super();
this.scope = scope;
}
@Override
public void handle(Annotation annotation, Field field, Object component) {
if (annotation.annotationType() != In.class) return;
String dependencyName = field.getName();
Object dependency = scope.getComponent(dependencyName);
if (dependency == null) return;
try {
if (!field.isAccessible()) field.setAccessible(true);
Object value = field.get(component);
if (value == dependency) return;
log.debug("Injecting component field:", component.getClass().getSimpleName() + "." + field.getName());
field.set(component, dependency);
} catch (Throwable ex) {
throw new DependencyInjectionFailedException(component, dependencyName, dependency, ex);
}
}
}
}