Isolated deployment becomes a feature exclusive to Java 8 thanks to Multi-Release Jar support. The DeploymentOptions fields are deprecated and documented to be removed when used with Java 11 or above. The documentation is removed. - closes #3274

This commit is contained in:
Julien Viet
2020-02-04 09:05:53 +01:00
parent 246be69028
commit 279922234e
14 changed files with 541 additions and 208 deletions

36
pom.xml
View File

@@ -281,10 +281,46 @@
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>default-jar</id>
<configuration>
<archive>
<manifestEntries>
<Multi-Release>true</Multi-Release>
</manifestEntries>
</archive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>jdk11</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<compileSourceRoots>
<compileSourceRoot>src/main/java11</compileSourceRoot>
</compileSourceRoots>
<outputDirectory>${project.build.outputDirectory}/META-INF/versions/11/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>

View File

@@ -357,23 +357,12 @@ Set the send timeout.
|[[config]]`@config`|`Json object`|+++
Set the JSON configuration that will be passed to the verticle(s) when it's deployed
+++
|[[extraClasspath]]`@extraClasspath`|`Array of String`|+++
Set any extra classpath to be used when deploying the verticle.
<p>
Ignored if no isolation group is set.
+++
|[[ha]]`@ha`|`Boolean`|+++
Set whether the verticle(s) will be deployed as HA.
+++
|[[instances]]`@instances`|`Number (int)`|+++
Set the number of instances that should be deployed.
+++
|[[isolatedClasses]]`@isolatedClasses`|`Array of String`|+++
Set the isolated class names.
+++
|[[isolationGroup]]`@isolationGroup`|`String`|+++
Set the isolation group that will be used when deploying the verticle(s)
+++
|[[maxWorkerExecuteTime]]`@maxWorkerExecuteTime`|`Number (long)`|+++
Sets the value of max worker execute time, in link.
<p>

View File

@@ -554,39 +554,6 @@ and multiple cores on your machine, so you want to deploy multiple instances to
include::override/verticle-configuration.adoc[]
=== Verticle Isolation Groups
By default, Vert.x has a _flat classpath_. I.e, when Vert.x deploys verticles it does so with the current classloader -
it doesn't create a new one. In the majority of cases this is the simplest, clearest, and sanest thing to do.
However, in some cases you may want to deploy a verticle so the classes of that verticle are isolated from others in
your application.
This might be the case, for example, if you want to deploy two different versions of a verticle with the same class name
in the same Vert.x instance, or if you have two different verticles which use different versions of the same jar library.
When using an isolation group you provide a list of the class names that you want isolated using
{@link io.vertx.core.DeploymentOptions#setIsolatedClasses(java.util.List)}- an entry can be a fully qualified
classname such as `com.mycompany.myproject.engine.MyClass` or it can be a wildcard which will match any classes in a package and any
sub-packages, e.g. `com.mycompany.myproject.*` would match any classes in the package `com.mycompany.myproject` or
any sub-packages.
Please note that _only_ the classes that match will be isolated - any other classes will be loaded by the current
class loader.
Extra classpath entries can also be provided with {@link io.vertx.core.DeploymentOptions#setExtraClasspath} so if
you want to load classes or resources that aren't already present on the main classpath you can add this.
WARNING: Use this feature with caution. Class-loaders can be a can of worms, and can make debugging difficult, amongst
other things.
Here's an example of using an isolation group to isolate a verticle deployment.
[source,$lang]
----
{@link examples.CoreExamples#example14}
----
=== High Availability
Verticles can be deployed with High Availability (HA) enabled. In that context, when a verticle is deployed on

View File

@@ -20,16 +20,6 @@ public class DeploymentOptionsConverter {
obj.setConfig(((JsonObject)member.getValue()).copy());
}
break;
case "extraClasspath":
if (member.getValue() instanceof JsonArray) {
java.util.ArrayList<java.lang.String> list = new java.util.ArrayList<>();
((Iterable<Object>)member.getValue()).forEach( item -> {
if (item instanceof String)
list.add((String)item);
});
obj.setExtraClasspath(list);
}
break;
case "ha":
if (member.getValue() instanceof Boolean) {
obj.setHa((Boolean)member.getValue());
@@ -40,21 +30,6 @@ public class DeploymentOptionsConverter {
obj.setInstances(((Number)member.getValue()).intValue());
}
break;
case "isolatedClasses":
if (member.getValue() instanceof JsonArray) {
java.util.ArrayList<java.lang.String> list = new java.util.ArrayList<>();
((Iterable<Object>)member.getValue()).forEach( item -> {
if (item instanceof String)
list.add((String)item);
});
obj.setIsolatedClasses(list);
}
break;
case "isolationGroup":
if (member.getValue() instanceof String) {
obj.setIsolationGroup((String)member.getValue());
}
break;
case "maxWorkerExecuteTime":
if (member.getValue() instanceof Number) {
obj.setMaxWorkerExecuteTime(((Number)member.getValue()).longValue());
@@ -92,21 +67,8 @@ public class DeploymentOptionsConverter {
if (obj.getConfig() != null) {
json.put("config", obj.getConfig());
}
if (obj.getExtraClasspath() != null) {
JsonArray array = new JsonArray();
obj.getExtraClasspath().forEach(item -> array.add(item));
json.put("extraClasspath", array);
}
json.put("ha", obj.isHa());
json.put("instances", obj.getInstances());
if (obj.getIsolatedClasses() != null) {
JsonArray array = new JsonArray();
obj.getIsolatedClasses().forEach(item -> array.add(item));
json.put("isolatedClasses", array);
}
if (obj.getIsolationGroup() != null) {
json.put("isolationGroup", obj.getIsolationGroup());
}
json.put("maxWorkerExecuteTime", obj.getMaxWorkerExecuteTime());
if (obj.getMaxWorkerExecuteTimeUnit() != null) {
json.put("maxWorkerExecuteTimeUnit", obj.getMaxWorkerExecuteTimeUnit().name());

View File

@@ -262,13 +262,6 @@ public class CoreExamples {
vertx.deployVerticle("com.mycompany.MyOrderProcessorVerticle", options);
}
public void example14(Vertx vertx) {
DeploymentOptions options = new DeploymentOptions().setIsolationGroup("mygroup");
options.setIsolatedClasses(Arrays.asList("com.mycompany.myverticle.*",
"com.mycompany.somepkg.SomeClass", "org.somelibrary.*"));
vertx.deployVerticle("com.mycompany.myverticle.VerticleClass", options);
}
public void example15(Vertx vertx) {
long timerID = vertx.setTimer(1000, id -> {
System.out.println("And one second later this is printed");

View File

@@ -12,6 +12,7 @@
package io.vertx.core;
import io.vertx.codegen.annotations.DataObject;
import io.vertx.codegen.annotations.GenIgnore;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
@@ -30,7 +31,6 @@ import java.util.concurrent.TimeUnit;
public class DeploymentOptions {
public static final boolean DEFAULT_WORKER = false;
public static final String DEFAULT_ISOLATION_GROUP = null;
public static final boolean DEFAULT_HA = false;
public static final int DEFAULT_INSTANCES = 1;
@@ -52,7 +52,7 @@ public class DeploymentOptions {
public DeploymentOptions() {
this.worker = DEFAULT_WORKER;
this.config = null;
this.isolationGroup = DEFAULT_ISOLATION_GROUP;
this.isolationGroup = null;
this.ha = DEFAULT_HA;
this.instances = DEFAULT_INSTANCES;
this.workerPoolName = null;
@@ -98,7 +98,7 @@ public class DeploymentOptions {
public void fromJson(JsonObject json) {
this.config = json.getJsonObject("config");
this.worker = json.getBoolean("worker", DEFAULT_WORKER);
this.isolationGroup = json.getString("isolationGroup", DEFAULT_ISOLATION_GROUP);
this.isolationGroup = json.getString("isolationGroup", null);
this.ha = json.getBoolean("ha", DEFAULT_HA);
JsonArray arr = json.getJsonArray("extraClasspath", null);
if (arr != null) {
@@ -153,19 +153,27 @@ public class DeploymentOptions {
/**
* Get the isolation group that will be used when deploying the verticle(s)
* <br/>
* <strong>IMPORTANT</strong> this feature is removed when running with Java 11 or above.
*
* @return the isolation group
*/
@GenIgnore
@Deprecated
public String getIsolationGroup() {
return isolationGroup;
}
/**
* Set the isolation group that will be used when deploying the verticle(s)
* <br/>
* <strong>IMPORTANT</strong> this feature is removed when running with Java 11 or above.
*
* @param isolationGroup - the isolation group
* @return a reference to this, so the API can be used fluently
*/
@GenIgnore
@Deprecated
public DeploymentOptions setIsolationGroup(String isolationGroup) {
this.isolationGroup = isolationGroup;
return this;
@@ -195,9 +203,13 @@ public class DeploymentOptions {
* Get any extra classpath to be used when deploying the verticle.
* <p>
* Ignored if no isolation group is set.
* <br/>
* <strong>IMPORTANT</strong> this feature is removed when running with Java 11 or above.
*
* @return any extra classpath
*/
@GenIgnore
@Deprecated
public List<String> getExtraClasspath() {
return extraClasspath;
}
@@ -206,9 +218,13 @@ public class DeploymentOptions {
* Set any extra classpath to be used when deploying the verticle.
* <p>
* Ignored if no isolation group is set.
* <br/>
* <strong>IMPORTANT</strong> this feature is removed when running with Java 11 or above.
*
* @return a reference to this, so the API can be used fluently
*/
@GenIgnore
@Deprecated
public DeploymentOptions setExtraClasspath(List<String> extraClasspath) {
this.extraClasspath = extraClasspath;
return this;
@@ -237,19 +253,27 @@ public class DeploymentOptions {
/**
* Get the list of isolated class names, the names can be a Java class fully qualified name such as
* 'com.mycompany.myproject.engine.MyClass' or a wildcard matching such as `com.mycompany.myproject.*`.
* <br/>
* <strong>IMPORTANT</strong> this feature is removed when running with Java 11 or above.
*
* @return the list of isolated classes
*/
@GenIgnore
@Deprecated
public List<String> getIsolatedClasses() {
return isolatedClasses;
}
/**
* Set the isolated class names.
* <br/>
* <strong>IMPORTANT</strong> this feature is removed when running with Java 11 or above.
*
* @param isolatedClasses the list of isolated class names
* @return a reference to this, so the API can be used fluently
*/
@GenIgnore
@Deprecated
public DeploymentOptions setIsolatedClasses(List<String> isolatedClasses) {
this.isolatedClasses = isolatedClasses;
return this;
@@ -348,6 +372,21 @@ public class DeploymentOptions {
return this;
}
/**
* Throw {@code IllegalArgumentException} when loader isolation configuration has been defined.
*/
public void checkIsolationNotDefined() {
if (getExtraClasspath() != null) {
throw new IllegalArgumentException("Can't specify extraClasspath for already created verticle");
}
if (getIsolationGroup() != null) {
throw new IllegalArgumentException("Can't specify isolationGroup for already created verticle");
}
if (getIsolatedClasses() != null) {
throw new IllegalArgumentException("Can't specify isolatedClasses for already created verticle");
}
}
/**
* Convert this to JSON
*

View File

@@ -0,0 +1,26 @@
/*
* 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.impl;
/**
* @author <a href="mailto:julien@julienviet.com">Julien Viet</a>
*/
class ClassLoaderHolder {
final String group;
final ClassLoader loader;
int refCount;
ClassLoaderHolder(String group, ClassLoader loader) {
this.group = group;
this.loader = loader;
}
}

View File

@@ -61,15 +61,7 @@ public class DeploymentManager {
if (options.getInstances() < 1) {
throw new IllegalArgumentException("Can't specify < 1 instances to deploy");
}
if (options.getExtraClasspath() != null) {
throw new IllegalArgumentException("Can't specify extraClasspath for already created verticle");
}
if (options.getIsolationGroup() != null) {
throw new IllegalArgumentException("Can't specify isolationGroup for already created verticle");
}
if (options.getIsolatedClasses() != null) {
throw new IllegalArgumentException("Can't specify isolatedClasses for already created verticle");
}
options.checkIsolationNotDefined();
ContextInternal currentContext = vertx.getOrCreateContext();
ClassLoader cl = getCurrentClassLoader();
return doDeploy(options, v -> "java:" + v.getClass().getName(), currentContext, currentContext, cl, verticleSupplier)

View File

@@ -26,12 +26,10 @@ public class IsolatingClassLoader extends URLClassLoader {
private volatile boolean closed;
private List<String> isolatedClasses;
int refCount;
public IsolatingClassLoader(URL[] urls, ClassLoader parent, List<String> isolatedClasses) {
super(urls, parent);
this.isolatedClasses = isolatedClasses;
this.refCount = 0;
}
@Override

View File

@@ -0,0 +1,99 @@
/*
* 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.impl;
import io.vertx.core.DeploymentOptions;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Supports isolated classloader for Java 8.
* <br/>
* For Java 11 and above, the JVM uses a no-op implementation thanks to Multi-Release Jar.
*/
class LoaderManager {
private final Map<String, ClassLoaderHolder> classLoaders = new HashMap<>();
/**
* <strong>IMPORTANT</strong> - Isolation groups are not supported on Java 9+ because the application classloader is not
* an URLClassLoader anymore. Thus we can't extract the list of jars to configure the IsolatedClassLoader.
*/
ClassLoaderHolder getClassLoader(DeploymentOptions options) {
String isolationGroup = options.getIsolationGroup();
ClassLoaderHolder holder;
if (isolationGroup == null) {
return null;
} else {
// IMPORTANT - Isolation groups are not supported on Java 9+, because the system classloader is not an URLClassLoader
// anymore. Thus we can't extract the paths from the classpath and isolate the loading.
synchronized (this) {
holder = classLoaders.get(isolationGroup);
if (holder == null) {
ClassLoader current = VerticleManager.getCurrentClassLoader();
if (!(current instanceof URLClassLoader)) {
throw new IllegalStateException("Current classloader must be URLClassLoader");
}
holder = new ClassLoaderHolder(isolationGroup, LoaderManager.buildLoader((URLClassLoader) current, options));
classLoaders.put(isolationGroup, holder);
}
holder.refCount++;
}
}
return holder;
}
void release(ClassLoaderHolder holder) {
synchronized (this) {
if (--holder.refCount == 0) {
classLoaders.remove(holder.group);
if (holder.loader instanceof Closeable) {
try {
((Closeable)holder.loader).close();
} catch (IOException e) {
// log.debug("Issue when closing isolation group loader", e);
}
}
}
}
}
private static ClassLoader buildLoader(URLClassLoader parent, DeploymentOptions options) {
List<URL> urls = new ArrayList<>();
// Add any extra URLs to the beginning of the classpath
List<String> extraClasspath = options.getExtraClasspath();
if (extraClasspath != null) {
for (String pathElement: extraClasspath) {
File file = new File(pathElement);
try {
URL url = file.toURI().toURL();
urls.add(url);
} catch (MalformedURLException e) {
throw new IllegalStateException(e);
}
}
}
// And add the URLs of the Vert.x classloader
urls.addAll(Arrays.asList(parent.getURLs()));
return new IsolatingClassLoader(urls.toArray(new URL[urls.size()]), parent,
options.getIsolatedClasses());
}
}

View File

@@ -17,15 +17,8 @@ import io.vertx.core.ServiceHelper;
import io.vertx.core.Verticle;
import io.vertx.core.spi.VerticleFactory;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -41,7 +34,7 @@ public class VerticleManager {
private final VertxInternal vertx;
private final DeploymentManager deploymentManager;
private final Map<String, IsolatingClassLoader> classloaders = new HashMap<>();
private final LoaderManager loaderManager = new LoaderManager();
private final Map<String, List<VerticleFactory>> verticleFactories = new ConcurrentHashMap<>();
private final List<VerticleFactory> defaultFactories = new ArrayList<>();
@@ -152,8 +145,23 @@ public class VerticleManager {
public Future<Deployment> deployVerticle(String identifier,
DeploymentOptions options) {
ContextInternal callingContext = vertx.getOrCreateContext();
ClassLoader cl = getClassLoader(options);
return doDeployVerticle(identifier, options, callingContext, callingContext, cl);
ClassLoaderHolder holder = loaderManager.getClassLoader(options);
ClassLoader loader = holder != null ? holder.loader : getCurrentClassLoader();
Future<Deployment> deployment = doDeployVerticle(identifier, options, callingContext, callingContext, loader);
if (holder != null) {
deployment.onComplete(ar -> {
if (ar.succeeded()) {
Deployment result = ar.result();
result.undeployHandler(v -> {
loaderManager.release(holder);
});
} else {
// ??? not tested
throw new UnsupportedOperationException();
}
});
}
return deployment;
}
private Future<Deployment> doDeployVerticle(String identifier,
@@ -204,88 +212,14 @@ public class VerticleManager {
} catch (Exception e) {
return Future.failedFuture(e);
}
Future<Deployment> fut = p.future().compose(callable -> deploymentManager.doDeploy(options, v -> identifier, parentContext, callingContext, cl, callable));
String group = options.getIsolationGroup();
if (group != null) {
fut.onComplete(ar -> {
if (ar.succeeded()) {
Deployment result = ar.result();
result.undeployHandler(v -> {
synchronized (VerticleManager.this) {
IsolatingClassLoader icl = classloaders.get(group);
if (--icl.refCount == 0) {
classloaders.remove(group);
try {
icl.close();
} catch (IOException e) {
// log.debug("Issue when closing isolation group loader", e);
}
}
}
});
} else {
// ??? not tested
throw new UnsupportedOperationException();
}
});
}
return fut;
return p.future()
.compose(callable -> deploymentManager.doDeploy(options, v -> identifier, parentContext, callingContext, cl, callable));
}
/**
* <strong>IMPORTANT</strong> - Isolation groups are not supported on Java 9+ because the application classloader is not
* an URLClassLoader anymore. Thus we can't extract the list of jars to configure the IsolatedClassLoader.
*
*/
private ClassLoader getClassLoader(DeploymentOptions options) {
String isolationGroup = options.getIsolationGroup();
ClassLoader cl;
if (isolationGroup == null) {
cl = getCurrentClassLoader();
} else {
// IMPORTANT - Isolation groups are not supported on Java 9+, because the system classloader is not an URLClassLoader
// anymore. Thus we can't extract the paths from the classpath and isolate the loading.
synchronized (this) {
IsolatingClassLoader icl = classloaders.get(isolationGroup);
if (icl == null) {
ClassLoader current = getCurrentClassLoader();
if (!(current instanceof URLClassLoader)) {
throw new IllegalStateException("Current classloader must be URLClassLoader");
}
List<URL> urls = new ArrayList<>();
// Add any extra URLs to the beginning of the classpath
List<String> extraClasspath = options.getExtraClasspath();
if (extraClasspath != null) {
for (String pathElement: extraClasspath) {
File file = new File(pathElement);
try {
URL url = file.toURI().toURL();
urls.add(url);
} catch (MalformedURLException e) {
throw new IllegalStateException(e);
}
}
}
// And add the URLs of the Vert.x classloader
URLClassLoader urlc = (URLClassLoader)current;
urls.addAll(Arrays.asList(urlc.getURLs()));
// Create an isolating cl with the urls
icl = new IsolatingClassLoader(urls.toArray(new URL[urls.size()]), getCurrentClassLoader(),
options.getIsolatedClasses());
classloaders.put(isolationGroup, icl);
}
icl.refCount++;
cl = icl;
}
}
return cl;
}
private ClassLoader getCurrentClassLoader() {
static ClassLoader getCurrentClassLoader() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null) {
cl = getClass().getClassLoader();
cl = VerticleManager.class.getClassLoader();
}
return cl;
}

View File

@@ -0,0 +1,286 @@
/*
* 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.codegen.annotations.DataObject;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Options for configuring a verticle deployment.
* <p>
*
*
* @author <a href="http://tfox.org">Tim Fox</a>
*/
@DataObject(generateConverter = true, publicConverter = false)
public class DeploymentOptions {
public static final boolean DEFAULT_WORKER = false;
public static final boolean DEFAULT_HA = false;
public static final int DEFAULT_INSTANCES = 1;
private JsonObject config;
private boolean worker;
private String workerPoolName;
private int workerPoolSize;
private long maxWorkerExecuteTime;
private boolean ha;
private int instances;
private TimeUnit maxWorkerExecuteTimeUnit;
/**
* Default constructor
*/
public DeploymentOptions() {
this.worker = DEFAULT_WORKER;
this.config = null;
this.ha = DEFAULT_HA;
this.instances = DEFAULT_INSTANCES;
this.workerPoolName = null;
this.workerPoolSize = VertxOptions.DEFAULT_WORKER_POOL_SIZE;
this.maxWorkerExecuteTime = VertxOptions.DEFAULT_MAX_WORKER_EXECUTE_TIME;
this.maxWorkerExecuteTimeUnit = VertxOptions.DEFAULT_MAX_WORKER_EXECUTE_TIME_UNIT;
}
/**
* Copy constructor
*
* @param other the instance to copy
*/
public DeploymentOptions(DeploymentOptions other) {
this.config = other.getConfig() == null ? null : other.getConfig().copy();
this.worker = other.isWorker();
this.ha = other.isHa();
this.instances = other.instances;
this.workerPoolName = other.workerPoolName;
setWorkerPoolSize(other.workerPoolSize);
setMaxWorkerExecuteTime(other.maxWorkerExecuteTime);
this.maxWorkerExecuteTimeUnit = other.maxWorkerExecuteTimeUnit;
}
/**
* Constructor for creating a instance from JSON
*
* @param json the JSON
*/
public DeploymentOptions(JsonObject json) {
this();
DeploymentOptionsConverter.fromJson(json, this);
}
/**
* Initialise the fields of this instance from the specified JSON
*
* @param json the JSON
*/
public void fromJson(JsonObject json) {
this.config = json.getJsonObject("config");
this.worker = json.getBoolean("worker", DEFAULT_WORKER);
this.ha = json.getBoolean("ha", DEFAULT_HA);
this.instances = json.getInteger("instances", DEFAULT_INSTANCES);
}
/**
* Get the JSON configuration that will be passed to the verticle(s) when deployed.
*
* @return the JSON config
*/
public JsonObject getConfig() {
return config;
}
/**
* Set the JSON configuration that will be passed to the verticle(s) when it's deployed
*
* @param config the JSON config
* @return a reference to this, so the API can be used fluently
*/
public DeploymentOptions setConfig(JsonObject config) {
this.config = config;
return this;
}
/**
* Should the verticle(s) be deployed as a worker verticle?
*
* @return true if will be deployed as worker, false otherwise
*/
public boolean isWorker() {
return worker;
}
/**
* Set whether the verticle(s) should be deployed as a worker verticle
*
* @param worker true for worker, false otherwise
* @return a reference to this, so the API can be used fluently
*/
public DeploymentOptions setWorker(boolean worker) {
this.worker = worker;
return this;
}
/**
* Will the verticle(s) be deployed as HA (highly available) ?
*
* @return true if HA, false otherwise
*/
public boolean isHa() {
return ha;
}
/**
* Set whether the verticle(s) will be deployed as HA.
*
* @param ha true if to be deployed as HA, false otherwise
* @return a reference to this, so the API can be used fluently
*/
public DeploymentOptions setHa(boolean ha) {
this.ha = ha;
return this;
}
/**
* Get the number of instances that should be deployed.
*
* @return the number of instances
*/
public int getInstances() {
return instances;
}
/**
* Set the number of instances that should be deployed.
*
* @param instances the number of instances
* @return a reference to this, so the API can be used fluently
*/
public DeploymentOptions setInstances(int instances) {
this.instances = instances;
return this;
}
/**
* @return the worker pool name
*/
public String getWorkerPoolName() {
return workerPoolName;
}
/**
* Set the worker pool name to use for this verticle. When no name is set, the Vert.x
* worker pool will be used, when a name is set, the verticle will use a named worker pool.
*
* @param workerPoolName the worker pool name
* @return a reference to this, so the API can be used fluently
*/
public DeploymentOptions setWorkerPoolName(String workerPoolName) {
this.workerPoolName = workerPoolName;
return this;
}
/**
* Get the maximum number of worker threads to be used by the worker pool when the verticle is deployed
* with a {@link #setWorkerPoolName}. When the verticle does not use a named worker pool, this option
* has no effect.
* <p>
* Worker threads are used for running blocking code and worker verticles.
*
* @return the maximum number of worker threads
*/
public int getWorkerPoolSize() {
return workerPoolSize;
}
/**
* Set the maximum number of worker threads to be used by the Vert.x instance.
*
* @param workerPoolSize the number of threads
* @return a reference to this, so the API can be used fluently
*/
public DeploymentOptions setWorkerPoolSize(int workerPoolSize) {
if (workerPoolSize < 1) {
throw new IllegalArgumentException("workerPoolSize must be > 0");
}
this.workerPoolSize = workerPoolSize;
return this;
}
/**
* Get the value of max worker execute time, in {@link DeploymentOptions#setMaxWorkerExecuteTimeUnit maxWorkerExecuteTimeUnit}.
* <p>
* Vert.x will automatically log a warning if it detects that worker threads haven't returned within this time.
* <p>
* This can be used to detect where the user is blocking a worker thread for too long. Although worker threads
* can be blocked longer than event loop threads, they shouldn't be blocked for long periods of time.
*
* @return The value of max worker execute time, the default value of {@link DeploymentOptions#setMaxWorkerExecuteTimeUnit} {@code maxWorkerExecuteTimeUnit} is {@link TimeUnit#NANOSECONDS}
*/
public long getMaxWorkerExecuteTime() {
return maxWorkerExecuteTime;
}
/**
* Sets the value of max worker execute time, in {@link DeploymentOptions#setMaxWorkerExecuteTimeUnit maxWorkerExecuteTimeUnit}.
* <p>
* The default value of {@link DeploymentOptions#setMaxWorkerExecuteTimeUnit maxWorkerExecuteTimeUnit} is {@link TimeUnit#NANOSECONDS}
*
* @param maxWorkerExecuteTime the value of max worker execute time, in in {@link DeploymentOptions#setMaxWorkerExecuteTimeUnit maxWorkerExecuteTimeUnit}.
* @return a reference to this, so the API can be used fluently
*/
public DeploymentOptions setMaxWorkerExecuteTime(long maxWorkerExecuteTime) {
if (maxWorkerExecuteTime < 1) {
throw new IllegalArgumentException("maxWorkerExecuteTime must be > 0");
}
this.maxWorkerExecuteTime = maxWorkerExecuteTime;
return this;
}
/**
* @return the time unit of {@code maxWorkerExecuteTime}
*/
public TimeUnit getMaxWorkerExecuteTimeUnit() {
return maxWorkerExecuteTimeUnit;
}
/**
* Set the time unit of {@code maxWorkerExecuteTime}
* @param maxWorkerExecuteTimeUnit the time unit of {@code maxWorkerExecuteTime}
* @return a reference to this, so the API can be used fluently
*/
public DeploymentOptions setMaxWorkerExecuteTimeUnit(TimeUnit maxWorkerExecuteTimeUnit) {
this.maxWorkerExecuteTimeUnit = maxWorkerExecuteTimeUnit;
return this;
}
/**
* Does nothing.
*/
public void checkIsolationNotDefined() {
}
/**
* Convert this to JSON
*
* @return the JSON
*/
public JsonObject toJson() {
JsonObject json = new JsonObject();
DeploymentOptionsConverter.toJson(this, json);
return json;
}
}

View File

@@ -0,0 +1,29 @@
/*
* 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.impl;
import io.vertx.core.DeploymentOptions;
/**
* No-op implementation for Java 11 and above.
*/
class LoaderManager {
/**
* @return {@code null}
*/
ClassLoaderHolder getClassLoader(DeploymentOptions options) {
return null;
}
void release(ClassLoaderHolder holder) {
}
}

View File

@@ -146,8 +146,6 @@ public class DeploymentTest extends VertxTestBase {
JsonObject config = new JsonObject().put("foo", "bar");
Random rand = new Random();
boolean worker = rand.nextBoolean();
boolean multiThreaded = rand.nextBoolean();
String isolationGroup = TestUtils.randomAlphaString(100);
boolean ha = rand.nextBoolean();
List<String> cp = Arrays.asList("foo", "bar");
List<String> isol = Arrays.asList("com.foo.MyClass", "org.foo.*");
@@ -158,22 +156,15 @@ public class DeploymentTest extends VertxTestBase {
JsonObject json = new JsonObject();
json.put("config", config);
json.put("worker", worker);
json.put("multiThreaded", multiThreaded);
json.put("isolationGroup", isolationGroup);
json.put("ha", ha);
json.put("extraClasspath", new JsonArray(cp));
json.put("isolatedClasses", new JsonArray(isol));
json.put("workerPoolName", poolName);
json.put("workerPoolSize", poolSize);
json.put("maxWorkerExecuteTime", maxWorkerExecuteTime);
json.put("maxWorkerExecuteTimeUnit", maxWorkerExecuteTimeUnit);
DeploymentOptions options = new DeploymentOptions(json);
assertEquals(worker, options.isWorker());
assertEquals(isolationGroup, options.getIsolationGroup());
assertEquals("bar", options.getConfig().getString("foo"));
assertEquals(ha, options.isHa());
assertEquals(cp, options.getExtraClasspath());
assertEquals(isol, options.getIsolatedClasses());
assertEquals(poolName, options.getWorkerPoolName());
assertEquals(poolSize, options.getWorkerPoolSize());
assertEquals(maxWorkerExecuteTime, options.getMaxWorkerExecuteTime());
@@ -186,8 +177,6 @@ public class DeploymentTest extends VertxTestBase {
JsonObject config = new JsonObject().put("foo", "bar");
Random rand = new Random();
boolean worker = rand.nextBoolean();
boolean multiThreaded = rand.nextBoolean();
String isolationGroup = TestUtils.randomAlphaString(100);
boolean ha = rand.nextBoolean();
List<String> cp = Arrays.asList("foo", "bar");
List<String> isol = Arrays.asList("com.foo.MyClass", "org.foo.*");
@@ -197,10 +186,7 @@ public class DeploymentTest extends VertxTestBase {
TimeUnit maxWorkerExecuteTimeUnit = TimeUnit.MILLISECONDS;
options.setConfig(config);
options.setWorker(worker);
options.setIsolationGroup(isolationGroup);
options.setHa(ha);
options.setExtraClasspath(cp);
options.setIsolatedClasses(isol);
options.setWorkerPoolName(poolName);
options.setWorkerPoolSize(poolSize);
options.setMaxWorkerExecuteTime(maxWorkerExecuteTime);
@@ -208,11 +194,8 @@ public class DeploymentTest extends VertxTestBase {
JsonObject json = options.toJson();
DeploymentOptions copy = new DeploymentOptions(json);
assertEquals(worker, copy.isWorker());
assertEquals(isolationGroup, copy.getIsolationGroup());
assertEquals("bar", copy.getConfig().getString("foo"));
assertEquals(ha, copy.isHa());
assertEquals(cp, copy.getExtraClasspath());
assertEquals(isol, copy.getIsolatedClasses());
assertEquals(poolName, copy.getWorkerPoolName());
assertEquals(poolSize, copy.getWorkerPoolSize());
assertEquals(maxWorkerExecuteTime, copy.getMaxWorkerExecuteTime());