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
|
||||
public final List<String> processArgs() {
|
||||
// As we are maintaining the launcher and starter class, choose the right one.
|
||||
List<String> processArgument = VertxCommandLauncher.getProcessArguments();
|
||||
return processArgument != null ? processArgument : Starter.PROCESS_ARGS;
|
||||
return VertxCommandLauncher.getProcessArguments();
|
||||
}
|
||||
|
||||
@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