io.vertx.up.uca.web.thread.AffluxThread Maven / Gradle / Ivy
package io.vertx.up.uca.web.thread;
import io.reactivex.Observable;
import io.vertx.up.annotations.Qualifier;
import io.vertx.up.eon.Plugins;
import io.vertx.up.log.Annal;
import io.vertx.up.eon.Values;
import io.vertx.zero.exception.MultiAnnotatedException;
import io.vertx.zero.exception.NamedImplementionException;
import io.vertx.zero.exception.NamedNotFoundException;
import io.vertx.zero.exception.QualifierMissedException;
import io.vertx.up.util.Ut;
import io.vertx.up.fn.Fn;
import javax.inject.Inject;
import javax.inject.Named;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
public class AffluxThread extends Thread {
private static final Annal LOGGER = Annal.get(AffluxThread.class);
private final ConcurrentMap> fieldMap = new ConcurrentHashMap<>();
private final transient Class> reference;
private final transient Set> namedSet;
private final transient Set> classes;
public AffluxThread(final Class> clazz, final Set> classes) {
this.setName("zero-injection-scanner-" + this.getId());
this.reference = clazz;
this.classes = classes;
this.namedSet = classes.stream()
.filter((item) -> item.isAnnotationPresent(Named.class))
.collect(Collectors.toSet());
}
@Override
public void run() {
if (null != this.reference) {
// 1. Read all inject point
final List fields = Arrays.stream(this.reference.getDeclaredFields())
.filter(field -> Plugins.INJECT_ANNOTATIONS.stream().anyMatch(field::isAnnotationPresent))
.collect(Collectors.toList());
// 2. Convert to fields
for (final Field field : fields) {
// 3. Specific
if (field.isAnnotationPresent(Inject.class)) {
this.scanStandard(field);
} else {
this.scanSpecific(field);
}
}
}
}
private void scanStandard(final Field field) {
// JSR 330
final Class> type = field.getType();
if (type.isInterface()) {
// Interface
final List> target = this.classes.stream().filter(
item -> Ut.isImplement(item, type)
).collect(Collectors.toList());
// Unique
if (Values.ONE == target.size()) {
final Class> targetCls = target.get(Values.IDX);
LOGGER.info(Info.SCANNED_FIELD, this.reference,
field.getName(), targetCls.getName(), Inject.class);
this.fieldMap.put(field.getName(), targetCls);
} else {
// By Named and Qualifier
this.scanQualifier(field, target);
}
} else {
this.fieldMap.put(field.getName(), type);
LOGGER.info(Info.SCANNED_FIELD, this.reference,
field.getName(), type.getName(), Inject.class);
}
}
private void scanQualifier(final Field field,
final List> instanceCls) {
// Log for instanceCls
final List instanceNames = instanceCls.stream().map(Class::getName).collect(Collectors.toList());
LOGGER.info(Info.SCANNED_INSTANCES, Ut.fromJoin(instanceNames));
// Field must annotated with @Qualifier
final Annotation annotation = field.getAnnotation(Qualifier.class);
Fn.outUp(null == annotation,
LOGGER, QualifierMissedException.class,
this.getClass(), field.getName(), field.getDeclaringClass().getName());
// All implementation class must be annotated with @Named
final boolean match = instanceCls.stream()
.allMatch(item -> item.isAnnotationPresent(Named.class));
final Set names = instanceCls.stream()
.map(Class::getName).collect(Collectors.toSet());
Fn.outUp(!match,
LOGGER, NamedImplementionException.class,
this.getClass(), names, field.getType().getName());
// Named value must be reflect with @Qualifier
final String value = Ut.invoke(annotation, "value");
final Optional> verified = instanceCls.stream()
.filter(item -> {
final Annotation target = item.getAnnotation(Named.class);
final String targetValue = Ut.invoke(target, "value");
return value.equals(targetValue)
&& !Ut.isNil(targetValue);
}).findAny();
Fn.outUp(!verified.isPresent(),
LOGGER, NamedNotFoundException.class,
this.getClass(), names, value);
// Passed all specification
this.fieldMap.put(field.getName(), verified.get());
}
private void scanSpecific(final Field field) {
// Vert.x Defined
final Set> defineds
= Plugins.INFIX_MAP.keySet();
final Annotation[] annotations = field.getDeclaredAnnotations();
// Annotation counter
final Set set = new HashSet<>();
final Annotation hitted = Observable.fromArray(annotations)
.filter(annotation -> defineds.contains(annotation.annotationType()))
.map(annotation -> {
set.add(annotation.annotationType().getName());
return annotation;
}).blockingFirst();
// Duplicated annotated
Fn.outUp(Values.ONE < set.size(), LOGGER,
MultiAnnotatedException.class, this.getClass(),
field.getName(), field.getDeclaringClass().getName(), set);
// Fill typed directly.
LOGGER.info(Info.SCANNED_FIELD, this.reference,
field.getName(),
field.getDeclaringClass().getName(),
hitted.annotationType().getName());
this.fieldMap.put(field.getName(), field.getType());
}
public ConcurrentMap> getFieldMap() {
return this.fieldMap;
}
public Class> getClassKey() {
return this.reference;
}
public boolean isEmpty() {
return this.fieldMap.isEmpty();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy