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

io.vertx.up.uca.rs.config.EventExtractor Maven / Gradle / Ivy

There is a newer version: 0.9.0
Show newest version
package io.vertx.up.uca.rs.config;

import io.reactivex.Observable;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.impl.ConcurrentHashSet;
import io.vertx.tp.error.EventCodexMultiException;
import io.vertx.up.annotations.Adjust;
import io.vertx.up.annotations.Codex;
import io.vertx.up.annotations.EndPoint;
import io.vertx.up.atom.agent.Event;
import io.vertx.up.fn.Fn;
import io.vertx.up.log.Annal;
import io.vertx.up.uca.rs.Extractor;
import io.vertx.up.runtime.ZeroHelper;
import io.vertx.up.uca.container.Virtual;
import io.vertx.up.util.Ut;
import io.vertx.zero.exception.EventSourceException;

import javax.ws.rs.Path;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Scanned @EndPoint clazz to build Event metadata
 */
public class EventExtractor implements Extractor> {

    private static final Annal LOGGER = Annal.get(EventExtractor.class);

    @Override
    public Set extract(final Class clazz) {
        return Fn.getNull(new ConcurrentHashSet<>(), () -> {
            // 1. Class verify
            verify(clazz);
            // 2. Check whether clazz annotated with @PATH
            final Set result = new ConcurrentHashSet<>();
            Fn.safeSemi(clazz.isAnnotationPresent(Path.class), LOGGER,
                    () -> {
                        // 3.1. Append Root Path
                        final Path path = ZeroHelper.getPath(clazz);
                        assert null != path : "Path should not be null.";
                        result.addAll(extract(clazz, PathResolver.resolve(path)));
                    },
                    () -> {
                        // 3.2. Use method Path directly
                        result.addAll(extract(clazz, null));
                    });
            return result;
        }, clazz);
    }

    private void verify(final Class clazz) {
        // Check basic specification: No Arg Constructor
        if (!clazz.isInterface()) {
            // Class direct.
            Verifier.noArg(clazz, getClass());
        }
        Verifier.modifier(clazz, getClass());
        // Event Source Checking
        Fn.outUp(!clazz.isAnnotationPresent(EndPoint.class),
                LOGGER, EventSourceException.class,
                getClass(), clazz.getName());
    }

    @SuppressWarnings("all")
    private Set extract(final Class clazz, final String root) {
        final Set events = new ConcurrentHashSet<>();
        // 0.Preparing
        final Method[] methods = clazz.getDeclaredMethods();
        // 1.Validate Codex annotation appears
        final Long counter = Observable.fromArray(methods)
                .map(Method::getParameterAnnotations)
                .flatMap(Observable::fromArray)
                .map(Arrays::asList)
                .map(item -> item.stream().map(Annotation::annotationType).collect(Collectors.toList()))
                .filter(item -> item.contains(Codex.class))
                .count().blockingGet();
        Fn.outUp(methods.length < counter, LOGGER,
                EventCodexMultiException.class,
                this.getClass(), clazz);
        // 2.Build Set
        events.addAll(Arrays.stream(methods).filter(MethodResolver::isValid)
                .map(item -> this.extract(item, root))
                .filter(Objects::nonNull)
                .collect(Collectors.toSet()));
        return events;
    }

    /**
     * Scan for single
     *
     * @param method single method that will be scanned.
     * @param root   root path calculation
     * @return Standard Event object
     */
    private Event extract(final Method method, final String root) {
        // 1.Method path
        final Event event = new Event();
        // 2.Method resolve
        final HttpMethod httpMethod = MethodResolver.resolve(method);
        if (null == httpMethod) {
            // Ignored the method could not be annotated.
            return null;
        } else {
            event.setMethod(httpMethod);
        }
        {
            // 3.1. Get path from method
            final Path path = ZeroHelper.getPath(method);
            if (null == path) {
                // 3.2. Check root double check
                if (!Ut.isNil(root)) {
                    // Use root directly.
                    event.setPath(root);
                }
            } else {
                final String result = PathResolver.resolve(
                        path, root);
                event.setPath(result);
            }
        }
        // 4.Action
        event.setAction(method);
        // 6.Mime resolve
        event.setConsumes(MediaResolver.consumes(method));
        event.setProduces(MediaResolver.produces(method));
        // 7. Instance clazz for proxy
        final Class clazz = method.getDeclaringClass();
        final Object proxy;
        if (clazz.isInterface()) {
            final Class implClass = Ut.childUnique(clazz);
            if (null != implClass) {
                proxy = Ut.singleton(implClass);
            } else {
                /*
                 * SPEC5: Interface only, direct api, in this situation,
                 * The proxy is null and the agent do nothing. The request will
                 * send to event bus direct. It's not needed to set
                 * implementation class.
                 */
                proxy = Virtual.create();
            }
        } else {
            proxy = Ut.singleton(method.getDeclaringClass());
        }
        event.setProxy(proxy);
        // 8. Order
        if (method.isAnnotationPresent(Adjust.class)) {
            final Annotation adjust = method.getDeclaredAnnotation(Adjust.class);
            final Integer order = Ut.invoke(adjust, "value");
            if (Objects.nonNull(order)) {
                /*
                 * Routing order modification.
                 */
                event.setOrder(order);
            }
        }
        return event;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy