All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vertx.up.uca.web.thread.AffluxThread Maven / Gradle / Ivy

There is a newer version: 0.9.0
Show newest version
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