mirror of
https://github.com/jlengrand/vert.x.git
synced 2026-03-10 08:51:19 +00:00
Merge pull request #3292 from tsegismont/starter-removal
Removed deprecated Starter class
This commit is contained in:
@@ -1,553 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2011-2019 Contributors to the Eclipse Foundation
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
|
||||||
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.vertx.core;
|
|
||||||
|
|
||||||
import io.vertx.core.impl.Args;
|
|
||||||
import io.vertx.core.impl.logging.Logger;
|
|
||||||
import io.vertx.core.impl.logging.LoggerFactory;
|
|
||||||
import io.vertx.core.json.DecodeException;
|
|
||||||
import io.vertx.core.json.JsonObject;
|
|
||||||
import io.vertx.core.metrics.MetricsOptions;
|
|
||||||
import io.vertx.core.spi.VertxMetricsFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.net.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
import java.util.jar.Attributes;
|
|
||||||
import java.util.jar.Manifest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@code main()} class that can be used to create Vert.x instance and deploy a verticle, or run a bare Vert.x instance.
|
|
||||||
* <p>
|
|
||||||
* This class is used by the {@code vertx} command line utility to deploy verticles from the command line.
|
|
||||||
* <p>
|
|
||||||
* E.g.
|
|
||||||
* <p>
|
|
||||||
* {@code vertx run myverticle.js}
|
|
||||||
* <p>
|
|
||||||
* It can also be used as the main class of an executable jar so you can run verticles directly with:
|
|
||||||
* <p>
|
|
||||||
* {@code java -jar myapp.jar}
|
|
||||||
*
|
|
||||||
* @author <a href="http://tfox.org">Tim Fox</a>
|
|
||||||
* @deprecated Use {@link Launcher} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class Starter {
|
|
||||||
|
|
||||||
public static final String VERTX_OPTIONS_PROP_PREFIX = "vertx.options.";
|
|
||||||
public static final String DEPLOYMENT_OPTIONS_PROP_PREFIX = "vertx.deployment.options.";
|
|
||||||
public static final String METRICS_OPTIONS_PROP_PREFIX = "vertx.metrics.options.";
|
|
||||||
|
|
||||||
private static final String PATH_SEP = System.getProperty("path.separator");
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(Starter.class);
|
|
||||||
public static List<String> PROCESS_ARGS;
|
|
||||||
|
|
||||||
public static void main(String[] sargs) {
|
|
||||||
Args args = new Args(sargs);
|
|
||||||
|
|
||||||
String extraCP = args.map.get("-cp");
|
|
||||||
if (extraCP != null) {
|
|
||||||
// If an extra CP is specified (e.g. to provide cp to a jar or cluster.xml) we must create a new classloader
|
|
||||||
// and run the starter using that so it's visible to the rest of the code
|
|
||||||
String[] parts = extraCP.split(PATH_SEP);
|
|
||||||
URL[] urls = new URL[parts.length];
|
|
||||||
for (int p = 0; p < parts.length; p++) {
|
|
||||||
String part = parts[p];
|
|
||||||
File file = new File(part);
|
|
||||||
try {
|
|
||||||
URL url = file.toURI().toURL();
|
|
||||||
urls[p] = url;
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ClassLoader icl = new URLClassLoader(urls, Starter.class.getClassLoader());
|
|
||||||
ClassLoader oldTCCL = Thread.currentThread().getContextClassLoader();
|
|
||||||
Thread.currentThread().setContextClassLoader(icl);
|
|
||||||
try {
|
|
||||||
Class<?> clazz = icl.loadClass(Starter.class.getName());
|
|
||||||
Object instance = clazz.newInstance();
|
|
||||||
Method run = clazz.getMethod("run", Args.class, String[].class);
|
|
||||||
run.invoke(instance, args, sargs);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
} finally {
|
|
||||||
Thread.currentThread().setContextClassLoader(oldTCCL);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No extra CP, just invoke directly
|
|
||||||
new Starter().run(args, sargs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void runCommandLine(String commandLine) {
|
|
||||||
new Starter().run(commandLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Vertx vertx;
|
|
||||||
protected VertxOptions options;
|
|
||||||
protected DeploymentOptions deploymentOptions;
|
|
||||||
|
|
||||||
protected void run(String commandLine) {
|
|
||||||
String[] sargs = commandLine.split(" ");
|
|
||||||
Args args = new Args(sargs);
|
|
||||||
run(args, sargs);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void run(String[] sargs) {
|
|
||||||
run(new Args(sargs), sargs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note! Must be public so can be called by reflection
|
|
||||||
public void run(Args args, String[] sargs) {
|
|
||||||
|
|
||||||
PROCESS_ARGS = Collections.unmodifiableList(Arrays.asList(sargs));
|
|
||||||
|
|
||||||
String main = readMainVerticleFromManifest();
|
|
||||||
if (main != null) {
|
|
||||||
runVerticle(main, args);
|
|
||||||
} else {
|
|
||||||
if (sargs.length > 0) {
|
|
||||||
String first = sargs[0];
|
|
||||||
if (first.equals("-version")) {
|
|
||||||
log.info(getVersion());
|
|
||||||
return;
|
|
||||||
} else if (first.equals("run")) {
|
|
||||||
if (sargs.length < 2) {
|
|
||||||
displaySyntax();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
main = sargs[1];
|
|
||||||
runVerticle(main, args);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if (first.equals("-ha")) {
|
|
||||||
// Create a bare instance
|
|
||||||
runBare(args);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
displaySyntax();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook for sub classes of {@link Starter} before the vertx instance is started.
|
|
||||||
*/
|
|
||||||
protected void beforeStartingVertx(VertxOptions options) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook for sub classes of {@link Starter} after the vertx instance is started.
|
|
||||||
*/
|
|
||||||
protected void afterStartingVertx() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook for sub classes of {@link Starter} before the verticle is deployed.
|
|
||||||
*/
|
|
||||||
protected void beforeDeployingVerticle(DeploymentOptions deploymentOptions) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A deployment failure has been encountered. You can override this method to customize the behavior.
|
|
||||||
* By default it closes the `vertx` instance.
|
|
||||||
*/
|
|
||||||
protected void handleDeployFailed() {
|
|
||||||
// Default behaviour is to close Vert.x if the deploy failed
|
|
||||||
vertx.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Vertx startVertx(boolean clustered, boolean ha, Args args) {
|
|
||||||
MetricsOptions metricsOptions;
|
|
||||||
ServiceLoader<VertxMetricsFactory> factories = ServiceLoader.load(VertxMetricsFactory.class);
|
|
||||||
if (factories.iterator().hasNext()) {
|
|
||||||
VertxMetricsFactory factory = factories.iterator().next();
|
|
||||||
metricsOptions = factory.newOptions();
|
|
||||||
} else {
|
|
||||||
metricsOptions = new MetricsOptions();
|
|
||||||
}
|
|
||||||
configureFromSystemProperties(metricsOptions, METRICS_OPTIONS_PROP_PREFIX);
|
|
||||||
options = new VertxOptions().setMetricsOptions(metricsOptions);
|
|
||||||
configureFromSystemProperties(options, VERTX_OPTIONS_PROP_PREFIX);
|
|
||||||
if (clustered) {
|
|
||||||
log.info("Starting clustering...");
|
|
||||||
int clusterPort = args.getInt("-cluster-port");
|
|
||||||
if (clusterPort == -1) {
|
|
||||||
// Default to zero - this means choose an ephemeral port
|
|
||||||
clusterPort = 0;
|
|
||||||
}
|
|
||||||
String clusterHost = args.map.get("-cluster-host");
|
|
||||||
if (clusterHost == null) {
|
|
||||||
clusterHost = getDefaultAddress();
|
|
||||||
if (clusterHost == null) {
|
|
||||||
log.error("Unable to find a default network interface for clustering. Please specify one using -cluster-host");
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
log.info("No cluster-host specified so using address " + clusterHost);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
|
||||||
AtomicReference<AsyncResult<Vertx>> result = new AtomicReference<>();
|
|
||||||
|
|
||||||
options.getEventBusOptions().setClustered(true).setHost(clusterHost).setPort(clusterPort);
|
|
||||||
if (ha) {
|
|
||||||
String haGroup = args.map.get("-hagroup");
|
|
||||||
int quorumSize = args.getInt("-quorum");
|
|
||||||
options.setHAEnabled(true);
|
|
||||||
if (haGroup != null) {
|
|
||||||
options.setHAGroup(haGroup);
|
|
||||||
}
|
|
||||||
if (quorumSize != -1) {
|
|
||||||
options.setQuorumSize(quorumSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
beforeStartingVertx(options);
|
|
||||||
Vertx.clusteredVertx(options, ar -> {
|
|
||||||
result.set(ar);
|
|
||||||
latch.countDown();
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
if (!latch.await(2, TimeUnit.MINUTES)) {
|
|
||||||
log.error("Timed out in starting clustered Vert.x");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
log.error("Thread interrupted in startup");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (result.get().failed()) {
|
|
||||||
log.error("Failed to form cluster", result.get().cause());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
vertx = result.get().result();
|
|
||||||
} else {
|
|
||||||
beforeStartingVertx(options);
|
|
||||||
vertx = Vertx.vertx(options);
|
|
||||||
}
|
|
||||||
addShutdownHook();
|
|
||||||
afterStartingVertx();
|
|
||||||
return vertx;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runBare(Args args) {
|
|
||||||
// ha is necessarily true here,
|
|
||||||
// so clustered is
|
|
||||||
Vertx vertx = startVertx(true, true, args);
|
|
||||||
if (vertx == null) {
|
|
||||||
// Throwable should have been logged at this point
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// As we do not deploy a verticle, other options are irrelevant (instances, worker, conf)
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runVerticle(String main, Args args) {
|
|
||||||
boolean ha = args.map.get("-ha") != null;
|
|
||||||
boolean clustered = args.map.get("-cluster") != null || ha;
|
|
||||||
|
|
||||||
Vertx vertx = startVertx(clustered, ha, args);
|
|
||||||
if (vertx == null) {
|
|
||||||
// Throwable should have been logged at this point
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String sinstances = args.map.get("-instances");
|
|
||||||
int instances;
|
|
||||||
if (sinstances != null) {
|
|
||||||
try {
|
|
||||||
instances = Integer.parseInt(sinstances);
|
|
||||||
|
|
||||||
if (instances != -1 && instances < 1) {
|
|
||||||
log.error("Invalid number of instances");
|
|
||||||
displaySyntax();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
displaySyntax();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
instances = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
String confArg = args.map.get("-conf");
|
|
||||||
JsonObject conf;
|
|
||||||
|
|
||||||
if (confArg != null) {
|
|
||||||
try (Scanner scanner = new Scanner(new File(confArg)).useDelimiter("\\A")){
|
|
||||||
String sconf = scanner.next();
|
|
||||||
try {
|
|
||||||
conf = new JsonObject(sconf);
|
|
||||||
} catch (DecodeException e) {
|
|
||||||
log.error("Configuration file " + sconf + " does not contain a valid JSON object");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
try {
|
|
||||||
conf = new JsonObject(confArg);
|
|
||||||
} catch (DecodeException e2) {
|
|
||||||
log.error("-conf option does not point to a file and is not valid JSON: " + confArg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
conf = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean worker = args.map.get("-worker") != null;
|
|
||||||
String message = (worker) ? "deploying worker verticle" : "deploying verticle";
|
|
||||||
deploymentOptions = new DeploymentOptions();
|
|
||||||
configureFromSystemProperties(deploymentOptions, DEPLOYMENT_OPTIONS_PROP_PREFIX);
|
|
||||||
|
|
||||||
deploymentOptions.setConfig(conf).setWorker(worker).setHa(ha).setInstances(instances);
|
|
||||||
|
|
||||||
beforeDeployingVerticle(deploymentOptions);
|
|
||||||
vertx.deployVerticle(main, deploymentOptions, createLoggingHandler(message, res -> {
|
|
||||||
if (res.failed()) {
|
|
||||||
// Failed to deploy
|
|
||||||
handleDeployFailed();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> Handler<AsyncResult<T>> createLoggingHandler(final String message, final Handler<AsyncResult<T>> completionHandler) {
|
|
||||||
return res -> {
|
|
||||||
if (res.failed()) {
|
|
||||||
Throwable cause = res.cause();
|
|
||||||
if (cause instanceof VertxException) {
|
|
||||||
VertxException ve = (VertxException)cause;
|
|
||||||
log.error(ve.getMessage());
|
|
||||||
if (ve.getCause() != null) {
|
|
||||||
log.error(ve.getCause());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.error("Failed in " + message, cause);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.info("Succeeded in " + message);
|
|
||||||
}
|
|
||||||
if (completionHandler != null) {
|
|
||||||
completionHandler.handle(res);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void configureFromSystemProperties(Object options, String prefix) {
|
|
||||||
Properties props = System.getProperties();
|
|
||||||
Enumeration e = props.propertyNames();
|
|
||||||
// Uhh, properties suck
|
|
||||||
while (e.hasMoreElements()) {
|
|
||||||
String propName = (String)e.nextElement();
|
|
||||||
String propVal = props.getProperty(propName);
|
|
||||||
if (propName.startsWith(prefix)) {
|
|
||||||
String fieldName = propName.substring(prefix.length());
|
|
||||||
Method setter = getSetter(fieldName, options.getClass());
|
|
||||||
if (setter == null) {
|
|
||||||
log.warn("No such property to configure on options: " + options.getClass().getName() + "." + fieldName);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Class<?> argType = setter.getParameterTypes()[0];
|
|
||||||
Object arg;
|
|
||||||
try {
|
|
||||||
if (argType.equals(String.class)) {
|
|
||||||
arg = propVal;
|
|
||||||
} else if (argType.equals(int.class)) {
|
|
||||||
arg = Integer.valueOf(propVal);
|
|
||||||
} else if (argType.equals(long.class)) {
|
|
||||||
arg = Long.valueOf(propVal);
|
|
||||||
} else if (argType.equals(boolean.class)) {
|
|
||||||
arg = Boolean.valueOf(propVal);
|
|
||||||
} else if (argType.isEnum()){
|
|
||||||
arg = Enum.valueOf((Class<? extends Enum>)argType, propVal);
|
|
||||||
} else {
|
|
||||||
log.warn("Invalid type for setter: " + argType);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} catch (IllegalArgumentException e2) {
|
|
||||||
log.warn("Invalid argtype:" + argType + " on options: " + options.getClass().getName() + "." + fieldName);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
setter.invoke(options, arg);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new VertxException("Failed to invoke setter: " + setter, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Method getSetter(String fieldName, Class<?> clazz) {
|
|
||||||
Method[] meths = clazz.getDeclaredMethods();
|
|
||||||
for (Method meth: meths) {
|
|
||||||
if (("set" + fieldName).toLowerCase().equals(meth.getName().toLowerCase())) {
|
|
||||||
return meth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addShutdownHook() {
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
|
||||||
public void run() {
|
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
|
||||||
vertx.close(ar -> {
|
|
||||||
if (!ar.succeeded()) {
|
|
||||||
log.error("Failure in stopping Vert.x", ar.cause());
|
|
||||||
}
|
|
||||||
latch.countDown();
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
if (!latch.await(2, TimeUnit.MINUTES)) {
|
|
||||||
log.error("Timed out waiting to undeploy all");
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Get default interface to use since the user hasn't specified one
|
|
||||||
*/
|
|
||||||
private String getDefaultAddress() {
|
|
||||||
Enumeration<NetworkInterface> nets;
|
|
||||||
try {
|
|
||||||
nets = NetworkInterface.getNetworkInterfaces();
|
|
||||||
} catch (SocketException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
NetworkInterface netinf;
|
|
||||||
while (nets.hasMoreElements()) {
|
|
||||||
netinf = nets.nextElement();
|
|
||||||
|
|
||||||
Enumeration<InetAddress> addresses = netinf.getInetAddresses();
|
|
||||||
|
|
||||||
while (addresses.hasMoreElements()) {
|
|
||||||
InetAddress address = addresses.nextElement();
|
|
||||||
if (!address.isAnyLocalAddress() && !address.isMulticastAddress()
|
|
||||||
&& !(address instanceof Inet6Address)) {
|
|
||||||
return address.getHostAddress();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVersion() {
|
|
||||||
try (InputStream is = getClass().getClassLoader().getResourceAsStream("META-INF/vertx/vertx-version.txt")) {
|
|
||||||
if (is == null) {
|
|
||||||
throw new IllegalStateException("Cannot find vertx-version.txt on classpath");
|
|
||||||
}
|
|
||||||
try (Scanner scanner = new Scanner(is, "UTF-8").useDelimiter("\\A")) {
|
|
||||||
return scanner.hasNext() ? scanner.next() : "";
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String readMainVerticleFromManifest() {
|
|
||||||
try {
|
|
||||||
Enumeration<URL> resources = getClass().getClassLoader().getResources("META-INF/MANIFEST.MF");
|
|
||||||
while (resources.hasMoreElements()) {
|
|
||||||
InputStream stream = null;
|
|
||||||
try {
|
|
||||||
stream = resources.nextElement().openStream();
|
|
||||||
Manifest manifest = new Manifest(stream);
|
|
||||||
Attributes attributes = manifest.getMainAttributes();
|
|
||||||
String mainClass = attributes.getValue("Main-Class");
|
|
||||||
if (Starter.class.getName().equals(mainClass)) {
|
|
||||||
String theMainVerticle = attributes.getValue("Main-Verticle");
|
|
||||||
if (theMainVerticle != null) {
|
|
||||||
return theMainVerticle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
closeQuietly(stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException(e.getMessage());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void closeQuietly(InputStream stream) {
|
|
||||||
if (stream != null) {
|
|
||||||
try {
|
|
||||||
stream.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// Ignore it.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displaySyntax() {
|
|
||||||
|
|
||||||
String usage =
|
|
||||||
|
|
||||||
" vertx run <main> [-options] \n" +
|
|
||||||
" runs a verticle called <main> in its own instance of vert.x. \n\n" +
|
|
||||||
" valid options are: \n" +
|
|
||||||
" -conf <config> Specifies configuration that should be provided \n" +
|
|
||||||
" to the verticle. <config> should reference \n" +
|
|
||||||
" either a text file containing a valid JSON \n" +
|
|
||||||
" object which represents the configuration OR \n" +
|
|
||||||
" be a JSON string. \n" +
|
|
||||||
" -instances <instances> specifies how many instances of the verticle \n" +
|
|
||||||
" will be deployed. Defaults to 1 \n" +
|
|
||||||
" -worker if specified then the verticle is a worker \n" +
|
|
||||||
" verticle. \n" +
|
|
||||||
" -cp <classpath> provide an extra classpath to be used for the \n" +
|
|
||||||
" verticle deployment. \n" +
|
|
||||||
" -cluster if specified then the vert.x instance will form \n" +
|
|
||||||
" a cluster with any other vert.x instances on \n" +
|
|
||||||
" the network. \n" +
|
|
||||||
" -cluster-port port to use for cluster communication. \n" +
|
|
||||||
" Default is 0 which means choose a spare \n" +
|
|
||||||
" random port. \n" +
|
|
||||||
" -cluster-host host to bind to for cluster communication. \n" +
|
|
||||||
" If this is not specified vert.x will attempt \n" +
|
|
||||||
" to choose one from the available interfaces. \n" +
|
|
||||||
" -ha if specified the verticle will be deployed as a \n" +
|
|
||||||
" high availability (HA) deployment. \n" +
|
|
||||||
" This means it can fail over to any other nodes \n" +
|
|
||||||
" in the cluster started with the same HA group \n" +
|
|
||||||
" -quorum used in conjunction with -ha this specifies the \n" +
|
|
||||||
" minimum number of nodes in the cluster for any \n" +
|
|
||||||
" HA deploymentIDs to be active. Defaults to 0 \n" +
|
|
||||||
" -hagroup used in conjunction with -ha this specifies the \n" +
|
|
||||||
" HA group this node will join. There can be \n" +
|
|
||||||
" multiple HA groups in a cluster. Nodes will only\n" +
|
|
||||||
" failover to other nodes in the same group. \n" +
|
|
||||||
" Defaults to __DEFAULT__ \n\n" +
|
|
||||||
|
|
||||||
" vertx -version \n" +
|
|
||||||
" displays the version";
|
|
||||||
|
|
||||||
log.info(usage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -218,9 +218,7 @@ abstract class AbstractContext implements ContextInternal {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final List<String> processArgs() {
|
public final List<String> processArgs() {
|
||||||
// As we are maintaining the launcher and starter class, choose the right one.
|
return VertxCommandLauncher.getProcessArguments();
|
||||||
List<String> processArgument = VertxCommandLauncher.getProcessArguments();
|
|
||||||
return processArgument != null ? processArgument : Starter.PROCESS_ARGS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,361 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2011-2019 Contributors to the Eclipse Foundation
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
|
||||||
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.vertx.core;
|
|
||||||
|
|
||||||
import io.vertx.core.impl.launcher.VertxCommandLauncher;
|
|
||||||
import io.vertx.core.json.JsonObject;
|
|
||||||
import io.vertx.core.spi.metrics.MetricsOptionsTest;
|
|
||||||
import io.vertx.test.core.VertxTestBase;
|
|
||||||
import io.vertx.test.verticles.TestVerticle;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.rules.TemporaryFolder;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="http://tfox.org">Tim Fox</a>
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public class StarterTest extends VertxTestBase {
|
|
||||||
|
|
||||||
Vertx vertx;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
TestVerticle.instanceCount.set(0);
|
|
||||||
TestVerticle.processArgs = null;
|
|
||||||
TestVerticle.conf = null;
|
|
||||||
|
|
||||||
VertxCommandLauncher.resetProcessArguments();
|
|
||||||
|
|
||||||
File manifest = new File("target/test-classes/META-INF/MANIFEST-Starter.MF");
|
|
||||||
if (!manifest.isFile()) {
|
|
||||||
throw new IllegalStateException("Cannot find the MANIFEST-Starter.MF file");
|
|
||||||
}
|
|
||||||
File target = new File("target/test-classes/META-INF/MANIFEST.MF");
|
|
||||||
Files.copy(manifest.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void tearDown() throws Exception {
|
|
||||||
clearProperties();
|
|
||||||
super.tearDown();
|
|
||||||
|
|
||||||
if (vertx != null) {
|
|
||||||
vertx.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testVersion() throws Exception {
|
|
||||||
String[] args = {"-version"};
|
|
||||||
MyStarter starter = new MyStarter();
|
|
||||||
starter.run(args);
|
|
||||||
assertEquals(System.getProperty("vertx.version"), starter.getVersion());
|
|
||||||
cleanup(starter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRunVerticle() throws Exception {
|
|
||||||
testRunVerticleMultiple(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRunVerticleMultipleInstances() throws Exception {
|
|
||||||
testRunVerticleMultiple(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testRunVerticleMultiple(int instances) throws Exception {
|
|
||||||
MyStarter starter = new MyStarter();
|
|
||||||
String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName(), "-instances", String.valueOf(instances)};
|
|
||||||
starter.run(args);
|
|
||||||
assertWaitUntil(() -> TestVerticle.instanceCount.get() == instances);
|
|
||||||
assertEquals(Arrays.asList(args), TestVerticle.processArgs);
|
|
||||||
starter.assertHooksInvoked();
|
|
||||||
cleanup(starter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRunVerticleClustered() throws Exception {
|
|
||||||
MyStarter starter = new MyStarter();
|
|
||||||
String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName(), "-cluster"};
|
|
||||||
starter.run(args);
|
|
||||||
assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1);
|
|
||||||
assertEquals(Arrays.asList(args), TestVerticle.processArgs);
|
|
||||||
starter.assertHooksInvoked();
|
|
||||||
cleanup(starter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRunVerticleHA() throws Exception {
|
|
||||||
MyStarter starter = new MyStarter();
|
|
||||||
String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName(), "-ha"};
|
|
||||||
starter.run(args);
|
|
||||||
assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1);
|
|
||||||
assertEquals(Arrays.asList(args), TestVerticle.processArgs);
|
|
||||||
starter.assertHooksInvoked();
|
|
||||||
cleanup(starter);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRunVerticleWithMainVerticleInManifestNoArgs() throws Exception {
|
|
||||||
MyStarter starter = new MyStarter();
|
|
||||||
String[] args = {};
|
|
||||||
starter.run(args);
|
|
||||||
assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1);
|
|
||||||
assertEquals(Arrays.asList(args), TestVerticle.processArgs);
|
|
||||||
cleanup(starter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cleanup(MyStarter starter) {
|
|
||||||
if (starter != null && starter.getVertx() != null) {
|
|
||||||
starter.getVertx().close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRunVerticleWithMainVerticleInManifestWithHA() throws Exception {
|
|
||||||
MyStarter starter = new MyStarter();
|
|
||||||
String[] args = {"-ha"};
|
|
||||||
starter.run(args);
|
|
||||||
assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1);
|
|
||||||
assertEquals(Arrays.asList(args), TestVerticle.processArgs);
|
|
||||||
cleanup(starter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRunVerticleWithMainVerticleInManifestWithArgs() throws Exception {
|
|
||||||
MyStarter starter = new MyStarter();
|
|
||||||
String[] args = {"-cluster", "-worker"};
|
|
||||||
starter.run(args);
|
|
||||||
assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1);
|
|
||||||
assertEquals(Arrays.asList(args), TestVerticle.processArgs);
|
|
||||||
cleanup(starter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRunVerticleWithConfString() throws Exception {
|
|
||||||
MyStarter starter = new MyStarter();
|
|
||||||
JsonObject conf = new JsonObject().put("foo", "bar").put("wibble", 123);
|
|
||||||
String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName(), "-conf", conf.encode()};
|
|
||||||
starter.run(args);
|
|
||||||
assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1);
|
|
||||||
assertEquals(conf, TestVerticle.conf);
|
|
||||||
cleanup(starter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public TemporaryFolder testFolder = new TemporaryFolder();
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRunVerticleWithConfFile() throws Exception {
|
|
||||||
Path tempDir = testFolder.newFolder().toPath();
|
|
||||||
Path tempFile = Files.createTempFile(tempDir, "conf", "json");
|
|
||||||
MyStarter starter = new MyStarter();
|
|
||||||
JsonObject conf = new JsonObject().put("foo", "bar").put("wibble", 123);
|
|
||||||
Files.write(tempFile, conf.encode().getBytes());
|
|
||||||
String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName(), "-conf", tempFile.toString()};
|
|
||||||
starter.run(args);
|
|
||||||
assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1);
|
|
||||||
assertEquals(conf, TestVerticle.conf);
|
|
||||||
cleanup(starter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testConfigureFromSystemProperties() throws Exception {
|
|
||||||
testConfigureFromSystemProperties(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testConfigureFromSystemPropertiesClustered() throws Exception {
|
|
||||||
testConfigureFromSystemProperties(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void testConfigureFromSystemProperties(boolean clustered) throws Exception {
|
|
||||||
|
|
||||||
// One for each type that we support
|
|
||||||
System.setProperty(Starter.VERTX_OPTIONS_PROP_PREFIX + "eventLoopPoolSize", "123");
|
|
||||||
System.setProperty(Starter.VERTX_OPTIONS_PROP_PREFIX + "maxEventLoopExecuteTime", "123767667");
|
|
||||||
System.setProperty(Starter.METRICS_OPTIONS_PROP_PREFIX + "enabled", "true");
|
|
||||||
System.setProperty(Starter.VERTX_OPTIONS_PROP_PREFIX + "haGroup", "somegroup");
|
|
||||||
System.setProperty(Starter.VERTX_OPTIONS_PROP_PREFIX + "maxEventLoopExecuteTimeUnit", "SECONDS");
|
|
||||||
|
|
||||||
MyStarter starter = new MyStarter();
|
|
||||||
String[] args;
|
|
||||||
if (clustered) {
|
|
||||||
args = new String[] {"run", "java:" + TestVerticle.class.getCanonicalName(), "-cluster"};
|
|
||||||
} else {
|
|
||||||
args = new String[] {"run", "java:" + TestVerticle.class.getCanonicalName()};
|
|
||||||
}
|
|
||||||
starter.run(args);
|
|
||||||
assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1);
|
|
||||||
|
|
||||||
VertxOptions opts = starter.getVertxOptions();
|
|
||||||
|
|
||||||
assertEquals(123, opts.getEventLoopPoolSize(), 0);
|
|
||||||
assertEquals(123767667L, opts.getMaxEventLoopExecuteTime());
|
|
||||||
assertEquals(true, opts.getMetricsOptions().isEnabled());
|
|
||||||
assertEquals("somegroup", opts.getHAGroup());
|
|
||||||
assertEquals(TimeUnit.SECONDS, opts.getMaxEventLoopExecuteTimeUnit());
|
|
||||||
|
|
||||||
cleanup(starter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clearProperties() {
|
|
||||||
Set<String> toClear = new HashSet<>();
|
|
||||||
Enumeration e = System.getProperties().propertyNames();
|
|
||||||
// Uhh, properties suck
|
|
||||||
while (e.hasMoreElements()) {
|
|
||||||
String propName = (String) e.nextElement();
|
|
||||||
if (propName.startsWith("vertx.options")) {
|
|
||||||
toClear.add(propName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (String propName : toClear) {
|
|
||||||
System.clearProperty(propName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCustomMetricsOptions() throws Exception {
|
|
||||||
System.setProperty(Starter.METRICS_OPTIONS_PROP_PREFIX + "enabled", "true");
|
|
||||||
System.setProperty(Starter.METRICS_OPTIONS_PROP_PREFIX + "customProperty", "customPropertyValue");
|
|
||||||
MyStarter starter = new MyStarter();
|
|
||||||
String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName()};
|
|
||||||
ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
|
|
||||||
Thread.currentThread().setContextClassLoader(MetricsOptionsTest.createMetricsFromMetaInfLoader("io.vertx.core.CustomMetricsFactory"));
|
|
||||||
try {
|
|
||||||
starter.run(args);
|
|
||||||
} finally {
|
|
||||||
Thread.currentThread().setContextClassLoader(oldCL);
|
|
||||||
}
|
|
||||||
assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1);
|
|
||||||
VertxOptions opts = starter.getVertxOptions();
|
|
||||||
CustomMetricsOptions custom = (CustomMetricsOptions) opts.getMetricsOptions();
|
|
||||||
assertEquals("customPropertyValue", custom.getCustomProperty());
|
|
||||||
|
|
||||||
cleanup(starter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testConfigureFromSystemPropertiesInvalidPropertyName() throws Exception {
|
|
||||||
|
|
||||||
System.setProperty(Starter.VERTX_OPTIONS_PROP_PREFIX + "nosuchproperty", "123");
|
|
||||||
|
|
||||||
// Should be ignored
|
|
||||||
|
|
||||||
MyStarter starter = new MyStarter();
|
|
||||||
String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName()};
|
|
||||||
starter.run(args);
|
|
||||||
assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1);
|
|
||||||
|
|
||||||
VertxOptions opts = starter.getVertxOptions();
|
|
||||||
VertxOptions def = new VertxOptions();
|
|
||||||
if (opts.getMetricsOptions().isEnabled()) {
|
|
||||||
def.getMetricsOptions().setEnabled(true);
|
|
||||||
}
|
|
||||||
assertEquals(def.toJson(), opts.toJson());
|
|
||||||
cleanup(starter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testConfigureFromSystemPropertiesInvalidPropertyType() throws Exception {
|
|
||||||
// One for each type that we support
|
|
||||||
System.setProperty(Starter.VERTX_OPTIONS_PROP_PREFIX + "eventLoopPoolSize", "sausages");
|
|
||||||
// Should be ignored
|
|
||||||
|
|
||||||
MyStarter starter = new MyStarter();
|
|
||||||
String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName()};
|
|
||||||
starter.run(args);
|
|
||||||
assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1);
|
|
||||||
|
|
||||||
VertxOptions opts = starter.getVertxOptions();
|
|
||||||
VertxOptions def = new VertxOptions();
|
|
||||||
if (opts.getMetricsOptions().isEnabled()) {
|
|
||||||
def.getMetricsOptions().setEnabled(true);
|
|
||||||
}
|
|
||||||
assertEquals(def.toJson(), opts.toJson());
|
|
||||||
cleanup(starter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRunWithCommandLine() throws Exception {
|
|
||||||
MyStarter starter = new MyStarter();
|
|
||||||
int instances = 10;
|
|
||||||
String cl = "run java:" + TestVerticle.class.getCanonicalName() + " -instances " + instances;
|
|
||||||
starter.run(cl);
|
|
||||||
assertWaitUntil(() -> TestVerticle.instanceCount.get() == instances);
|
|
||||||
cleanup(starter);
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyStarter extends Starter {
|
|
||||||
boolean beforeStartingVertxInvoked = false;
|
|
||||||
boolean afterStartingVertxInvoked = false;
|
|
||||||
boolean beforeDeployingVerticle = false;
|
|
||||||
|
|
||||||
public Vertx getVertx() {
|
|
||||||
return vertx;
|
|
||||||
}
|
|
||||||
|
|
||||||
public VertxOptions getVertxOptions() {
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DeploymentOptions getDeploymentOptions() {
|
|
||||||
return deploymentOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(String[] sargs) {
|
|
||||||
super.run(sargs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(String commandLine) {
|
|
||||||
super.run(commandLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void beforeStartingVertx(VertxOptions options) {
|
|
||||||
beforeStartingVertxInvoked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterStartingVertx() {
|
|
||||||
afterStartingVertxInvoked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void beforeDeployingVerticle(DeploymentOptions deploymentOptions) {
|
|
||||||
beforeDeployingVerticle = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assertHooksInvoked() {
|
|
||||||
StarterTest.this.vertx = vertx;
|
|
||||||
assertTrue(beforeStartingVertxInvoked);
|
|
||||||
assertTrue(afterStartingVertxInvoked);
|
|
||||||
assertTrue(beforeDeployingVerticle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
Main-Class: io.vertx.core.Starter
|
|
||||||
Main-Verticle: java:io.vertx.test.verticles.TestVerticle
|
|
||||||
Reference in New Issue
Block a user