org.mustertech.webapp.vertxutils.VerticleDeployer.java Source code

Java tutorial

Introduction

Here is the source code for org.mustertech.webapp.vertxutils.VerticleDeployer.java

Source

/*
 * Copyright (c) 2016. The original author or authors
 *
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Apache License v2.0
 *  which accompanies this distribution.
 *
 *  The Apache License v2.0 is available at
 *  http://www.opensource.org/licenses/apache2.0.php
 *
 *  You may elect to redistribute this code under the above mentioned license.
 */
package org.mustertech.webapp.vertxutils;

import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Iterator;

import org.apache.commons.io.IOUtils;

import org.jdeferred.Deferred;
import org.jdeferred.DeferredManager;
import org.jdeferred.DoneCallback;
import org.jdeferred.FailCallback;
import org.jdeferred.Promise;
import org.jdeferred.impl.DefaultDeferredManager;
import org.jdeferred.impl.DeferredObject;
import org.jdeferred.multiple.MultipleResults;
import org.jdeferred.multiple.OneReject;
import org.jdeferred.multiple.OneResult;

import io.vertx.core.json.JsonArray;
import io.vertx.core.AsyncResult;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;

/*
* Represents verticle deployment helper class.
* <p>
* Any vert.x based projects using verticles, can import this module. Typical and recommended usage is,
* to create a verticle named "AppVerticle" for your project and use this class to deploy rest of
* the verticles using a deployment specification json file. The json file can be passed as command line
* argument with the vert.x's -conf option.
* <p>
* The required format of json deployment configuration file follows json-schema as defined in deploy-schema.json
*/
public final class VerticleDeployer {
    private static Vertx vertx = null;

    /*
    * Create an AsyncResult object and return it, for a generic type T
    *
    * @param cause An object of type Throwable
    * @param result A generic type object
    * @return AsyncResult object
    */
    private static <T> AsyncResult<T> makeAsyncResult(Throwable cause, T result) {
        AsyncResult<T> ar;

        if (null != cause) {
            ar = new AsyncResult<T>() {
                public Throwable cause() {
                    return cause;
                }

                public boolean failed() {
                    return true;
                }

                public T result() {
                    return null;
                }

                public boolean succeeded() {
                    return false;
                }
            };
        } else {
            ar = new AsyncResult<T>() {
                public Throwable cause() {
                    return null;
                }

                public boolean failed() {
                    return false;
                }

                public T result() {
                    return result;
                }

                public boolean succeeded() {
                    return true;
                }
            };
        }

        return ar;
    }

    /*
    * Deploy a verticle with given deployment configuration
    *
    * @param opt Json object representing the verticle deployment configuration
    * @return Promise object
    * */
    private static Promise<JsonObject, Exception, Double> deployWithOpts(JsonObject opt) {
        Deferred<JsonObject, Exception, Double> deffered = new DeferredObject<JsonObject, Exception, Double>();
        DeploymentOptions deployOpts = new DeploymentOptions();

        // Check and set Config option
        if (opt.containsKey("config")) {
            JsonObject vertCfg = opt.getJsonObject("config");
            deployOpts.setConfig(vertCfg);
        }

        // Check and set ExtraClasspath option
        if (opt.containsKey("extCps")) {
            JsonArray extCps = opt.getJsonArray("extCps");
            Iterator<Object> cpIter = extCps.iterator();

            ArrayList<String> extCpsList = new ArrayList<String>();
            while (cpIter.hasNext()) {
                extCpsList.add((String) cpIter.next());
            }

            deployOpts.setExtraClasspath(extCpsList);
        }

        // Check and set Isolated-Group option
        if (opt.containsKey("isolatedGrp")) {
            deployOpts.setIsolationGroup(opt.getString("isolatedGrp"));
        }

        // Check and set Isolated-Classes option
        if (opt.containsKey("isolatedCls")) {
            JsonArray isoCls = opt.getJsonArray("isolatedCls");
            Iterator<Object> clsIter = isoCls.iterator();

            ArrayList<String> isoClsList = new ArrayList<String>();
            while (clsIter.hasNext()) {
                isoClsList.add((String) clsIter.next());
            }

            deployOpts.setIsolatedClasses(isoClsList);
        }

        // Check and set HA option
        deployOpts.setHa(opt.containsKey("isHa") && opt.getBoolean("isHa"));

        // Check and set instances option
        deployOpts.setInstances(opt.containsKey("nInst") ? opt.getInteger("nInst").intValue() : 1);

        // Check and set Worker/MT option
        Boolean isWorker = (opt.containsKey("isWorker") && opt.getBoolean("isWorker"));
        if (isWorker) {
            deployOpts.setWorker(true);
            deployOpts.setMultiThreaded(opt.containsKey("isMt") && opt.getBoolean("isMt"));
        }

        String vertName = opt.getString("name");

        // Finally, deploy the verticle
        vertx.deployVerticle(vertName, deployOpts, ar -> {
            if (ar.succeeded()) {
                JsonObject resObj = new JsonObject();
                resObj.put("verticleName", vertName).put("deployId", ar.result());

                deffered.resolve(resObj);
            } else {
                Throwable thr = ar.cause();
                String defErr = vertName + " => Could not be deployed!";
                deffered.reject(
                        (null != thr.getMessage()) ? new Exception(thr.getMessage()) : new Exception(defErr));
            }
        });

        return deffered.promise();
    }

    /*
    * Method to deploy a set of verticles based on deployment configuration file
    *
    * @param vertx Vertx instance being used to deploy the verticle(s)
    * @param cfgJson String representation of the Json object defining the deployment configuration
    * @param handler AsyncResult handler which can be called to indicate the completion of deployment
    */
    public static void deploy(final Vertx vertx, final String cfgJson, Handler<AsyncResult<JsonObject>> handler) {
        if (null == vertx) {
            NullPointerException e = new NullPointerException("NULL vertxutils instance is passed!");
            handler.handle(makeAsyncResult(e, null));

            return;
        }

        // Store the vertx instance
        VerticleDeployer.vertx = vertx;

        try {
            InputStream schStream = VerticleDeployer.class.getResourceAsStream("/schema/deploy-schema.json");
            StringWriter strWriter = new StringWriter();

            IOUtils.copy(schStream, strWriter, "UTF-8");
            JsonValidator.validateJson(strWriter.toString(), cfgJson);
            IOUtils.closeQuietly(schStream);

            JsonObject cfgObj = new JsonObject(cfgJson);
            JsonObject globalCfg = null;
            JsonObject optObj = null, optCfg = null;
            JsonArray deployOpts = cfgObj.getJsonArray("deployOpts");

            int optsLen = deployOpts.size();
            ArrayList<Promise<JsonObject, Exception, Double>> promises = new ArrayList<Promise<JsonObject, Exception, Double>>();

            if (cfgObj.containsKey("globalConf")) {
                globalCfg = cfgObj.getJsonObject("globalConf");
            }

            for (int idx = 0; idx < optsLen; idx++) {
                optObj = (JsonObject) deployOpts.getJsonObject(idx);

                if (cfgObj.containsKey("appendGlobal") && cfgObj.getBoolean("appendGlobal")) {
                    if (optObj.containsKey("config")) {
                        optCfg = optObj.getJsonObject("config");

                        if (!optCfg.containsKey("global")) {
                            optCfg.put("global", globalCfg);
                        }
                    } else {
                        optCfg = new JsonObject();

                        optCfg.put("global", globalCfg);
                        optObj.put("config", optCfg);
                    }
                }

                promises.add(deployWithOpts(optObj));
            }

            DeferredManager defMgr = new DefaultDeferredManager();

            defMgr.when(promises.toArray(new Promise[] {})).done(new DoneCallback<MultipleResults>() {
                public void onDone(MultipleResults results) {
                    JsonArray resArr = new JsonArray();
                    Iterator<OneResult> oneResIter = results.iterator();

                    while (oneResIter.hasNext()) {
                        resArr.add(oneResIter.next().getResult());
                    }

                    JsonObject resObj = new JsonObject();
                    resObj.put("deployInfo", resArr);

                    handler.handle(makeAsyncResult(null, resObj));
                }
            }).fail(new FailCallback<OneReject>() {
                public void onFail(OneReject err) {
                    handler.handle(makeAsyncResult((Throwable) err.getReject(), null));
                }
            });
        } catch (Exception e) {
            handler.handle(makeAsyncResult(e, null));
        }
    }
}