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

io.vertx.up.VertxApplication Maven / Gradle / Ivy

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

import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.tp.plugin.etcd.center.EtcdData;
import io.vertx.up.annotations.Up;
import io.vertx.up.eon.em.ServerType;
import io.vertx.up.exception.zero.EtcdNetworkException;
import io.vertx.up.fn.Fn;
import io.vertx.up.log.Annal;
import io.vertx.up.runtime.Anno;
import io.vertx.up.runtime.Runner;
import io.vertx.up.runtime.ZeroAnno;
import io.vertx.up.runtime.ZeroHeart;
import io.vertx.up.uca.options.DynamicVisitor;
import io.vertx.up.uca.options.ServerVisitor;
import io.vertx.up.util.Ut;
import io.vertx.up.uca.web.ZeroLauncher;
import io.vertx.up.uca.web.anima.*;
import io.vertx.zero.exception.MicroModeUpException;
import io.vertx.zero.exception.UpClassArgsException;
import io.vertx.zero.exception.UpClassInvalidException;

import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;

/**
 * Vertx Application entry
 * 1) VertxApplication: start up zero framework in `application` mode. ( Service | Application )
 * 2) MicroApplication: start up zero framework in `micro` mode. ( Service & Gateway )
 * 3) Five scanners for critical components starting up
 */
public class VertxApplication {

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

    private transient final Class clazz;

    private final transient ConcurrentMap annotationMap;

    private VertxApplication(final Class clazz) {
        /*
         * Although the input `clazz` is not important, but zero container require the input
         * clazz mustn't be null, for future usage such as plugin extension for it.
         */
        Fn.out(null == clazz, UpClassArgsException.class, getClass());

        /*
         * Stored clazz information
         * 1. clazz stored
         * 2. annotation extraction from Annotation[] -> Annotation Map
         */
        this.clazz = clazz;
        annotationMap = Anno.get(clazz);

        /*
         * Zero specification definition for @Up here.
         * The input class must annotated with @Up instead of other description
         */

        Fn.out(!annotationMap.containsKey(Up.class.getName()), UpClassInvalidException.class, getClass(),
                null == this.clazz ? null : this.clazz.getName());
    }

    public static void run(final Class clazz, final Object... args) {
        Fn.shuntRun(() -> {
            /*
             * Class definition predicate
             */
            ensureEtcd(clazz);
            /*
             * To avoid getPackages issue here
             * Move to InitScatter here
             */
            ZeroHeart.init();

            /*
             * Before launcher, start package scanning for preparing metadata
             * This step is critical because it's environment core preparing steps.
             * 1) Before vert.x started, the system must be scanned all to capture some metadata classes instead.
             * 2) PackScan will scan all classes to capture Annotation information
             * 3) For zero extension module, although it's not in ClassLoader, we also need to scan dependency library
             *    to capture zero extension module annotation
             *
             * Because static {} initializing will be triggered when `ZeroAnno` is called first time, to avoid
             * some preparing failure, here we replaced `static {}` with `prepare()` calling before any instance
             * of VertxApplication/MicroApplication.
             */
            ZeroAnno.prepare();

            /*
             * Then the container could start
             */
            if (isGateway()) {
                /*
                 * Api Gateway:
                 * `Micro` mode only
                 * Current zero node will run as api gateway
                 */
                MicroApplication.run(clazz);
            } else {
                /*
                 * Standard application
                 * 1. In `Micro` mode, it will run as service node.
                 * 2. In `Standalone` mode, it will run as application.
                 */
                new VertxApplication(clazz).run(args);
            }
        }, LOGGER);
    }

    private static boolean isGateway() {
        /*
         * This method is only ok when `micro` mode
         * Secondary Scanned for Api Gateway
         */
        final Set apiScanned = new HashSet<>();
        Fn.outUp(() -> {
            final ServerVisitor visitor =
                    Ut.singleton(DynamicVisitor.class);
            apiScanned.addAll(visitor.visit(ServerType.API.toString()).keySet());
        }, LOGGER);
        return !apiScanned.isEmpty();
    }

    private static void ensureEtcd(final Class clazz) {
        /*
         * Whether startup etcd environment
         * 1) Etcd environment depend on `vertx-micro.yml`
         * 2) If it's start up, zero container must check etcd configuration and try to connect
         * 3) Zero will initialize etcd nodes information for current micro environment.
         */
        if (EtcdData.enabled()) {
            try {
                EtcdData.create(clazz);
            } catch (final EtcdNetworkException ex) {
                Fn.outUp(true, LOGGER,
                        MicroModeUpException.class, clazz, ex.getMessage());
            }
        }
    }

    private void run(final Object... args) {

        final Launcher launcher = Ut.singleton(ZeroLauncher.class);
        launcher.start(vertx -> {
            /* 1.Find Agent for deploy **/
            Runner.run(() -> {
                final Scatter scatter = Ut.singleton(AgentScatter.class);
                scatter.connect(vertx);
            }, "agent-runner");

            /* 2.Find Worker for deploy **/
            Runner.run(() -> {
                final Scatter scatter = Ut.singleton(WorkerScatter.class);
                scatter.connect(vertx);
            }, "worker-runner");

            /* 3.Initialize Infix **/
            Runner.run(() -> {
                // Infix
                Scatter scatter = Ut.singleton(InfixScatter.class);
                scatter.connect(vertx);
                // Injection
                scatter = Ut.singleton(AffluxScatter.class);
                scatter.connect(vertx);
            }, "infix-afflux-runner");

            /* 4.Rule started **/
            Runner.run(() -> {
                final Scatter scatter = Ut.singleton(CodexScatter.class);
                scatter.connect(vertx);
            }, "codex-engine-runner");

            /* 5.Plugin init */
            /*
            Runner.run(() -> {
                final Scatter scatter = Ut.singleton(InitScatter.class);
                scatter.connect(vertx);
            }, "initializer-runner");*/
        });
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy