diff --git a/pom.xml b/pom.xml index 397b62f56..2be70d828 100644 --- a/pom.xml +++ b/pom.xml @@ -281,10 +281,46 @@ + + org.apache.maven.plugins + maven-jar-plugin + + + default-jar + + + + true + + + + + + + + + maven-compiler-plugin + + + jdk11 + compile + + compile + + + + src/main/java11 + + ${project.build.outputDirectory}/META-INF/versions/11/ + + + + + org.bsc.maven maven-processor-plugin diff --git a/src/main/asciidoc/dataobjects.adoc b/src/main/asciidoc/dataobjects.adoc index 95a2138a9..bab5b58a6 100644 --- a/src/main/asciidoc/dataobjects.adoc +++ b/src/main/asciidoc/dataobjects.adoc @@ -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. -

- 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.

diff --git a/src/main/asciidoc/index.adoc b/src/main/asciidoc/index.adoc index d99a09ce9..89ce299d1 100644 --- a/src/main/asciidoc/index.adoc +++ b/src/main/asciidoc/index.adoc @@ -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 diff --git a/src/main/generated/io/vertx/core/DeploymentOptionsConverter.java b/src/main/generated/io/vertx/core/DeploymentOptionsConverter.java index 4862b055d..4ef5ea882 100644 --- a/src/main/generated/io/vertx/core/DeploymentOptionsConverter.java +++ b/src/main/generated/io/vertx/core/DeploymentOptionsConverter.java @@ -20,16 +20,6 @@ public class DeploymentOptionsConverter { obj.setConfig(((JsonObject)member.getValue()).copy()); } break; - case "extraClasspath": - if (member.getValue() instanceof JsonArray) { - java.util.ArrayList list = new java.util.ArrayList<>(); - ((Iterable)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 list = new java.util.ArrayList<>(); - ((Iterable)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()); diff --git a/src/main/java/examples/CoreExamples.java b/src/main/java/examples/CoreExamples.java index 8b835f264..051719e93 100644 --- a/src/main/java/examples/CoreExamples.java +++ b/src/main/java/examples/CoreExamples.java @@ -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"); diff --git a/src/main/java/io/vertx/core/DeploymentOptions.java b/src/main/java/io/vertx/core/DeploymentOptions.java index 091e7ab31..bdbe6069d 100644 --- a/src/main/java/io/vertx/core/DeploymentOptions.java +++ b/src/main/java/io/vertx/core/DeploymentOptions.java @@ -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,14 +98,14 @@ 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"); this.ha = json.getBoolean("ha", DEFAULT_HA); - JsonArray arr = json.getJsonArray("extraClasspath", null); + JsonArray arr = json.getJsonArray("extraClasspath"); if (arr != null) { this.extraClasspath = arr.getList(); } this.instances = json.getInteger("instances", DEFAULT_INSTANCES); - JsonArray arrIsolated = json.getJsonArray("isolatedClasses", null); + JsonArray arrIsolated = json.getJsonArray("isolatedClasses"); if (arrIsolated != null) { this.isolatedClasses = arrIsolated.getList(); } @@ -153,19 +153,27 @@ public class DeploymentOptions { /** * Get the isolation group that will be used when deploying the verticle(s) + *
+ * IMPORTANT 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) + *
+ * IMPORTANT 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. *

* Ignored if no isolation group is set. + *
+ * IMPORTANT this feature is removed when running with Java 11 or above. * * @return any extra classpath */ + @GenIgnore + @Deprecated public List getExtraClasspath() { return extraClasspath; } @@ -206,9 +218,13 @@ public class DeploymentOptions { * Set any extra classpath to be used when deploying the verticle. *

* Ignored if no isolation group is set. + *
+ * IMPORTANT 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 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.*`. + *
+ * IMPORTANT this feature is removed when running with Java 11 or above. * * @return the list of isolated classes */ + @GenIgnore + @Deprecated public List getIsolatedClasses() { return isolatedClasses; } /** * Set the isolated class names. + *
+ * IMPORTANT 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 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 * diff --git a/src/main/java/io/vertx/core/impl/ClassLoaderHolder.java b/src/main/java/io/vertx/core/impl/ClassLoaderHolder.java new file mode 100644 index 000000000..2566dfc5d --- /dev/null +++ b/src/main/java/io/vertx/core/impl/ClassLoaderHolder.java @@ -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 Julien Viet + */ +class ClassLoaderHolder { + + final String group; + final ClassLoader loader; + int refCount; + + ClassLoaderHolder(String group, ClassLoader loader) { + this.group = group; + this.loader = loader; + } +} diff --git a/src/main/java/io/vertx/core/impl/DeploymentManager.java b/src/main/java/io/vertx/core/impl/DeploymentManager.java index fb0df3d30..19037f502 100644 --- a/src/main/java/io/vertx/core/impl/DeploymentManager.java +++ b/src/main/java/io/vertx/core/impl/DeploymentManager.java @@ -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) diff --git a/src/main/java/io/vertx/core/impl/IsolatingClassLoader.java b/src/main/java/io/vertx/core/impl/IsolatingClassLoader.java index 58f707812..e8420cf0e 100644 --- a/src/main/java/io/vertx/core/impl/IsolatingClassLoader.java +++ b/src/main/java/io/vertx/core/impl/IsolatingClassLoader.java @@ -26,12 +26,10 @@ public class IsolatingClassLoader extends URLClassLoader { private volatile boolean closed; private List isolatedClasses; - int refCount; public IsolatingClassLoader(URL[] urls, ClassLoader parent, List isolatedClasses) { super(urls, parent); this.isolatedClasses = isolatedClasses; - this.refCount = 0; } @Override diff --git a/src/main/java/io/vertx/core/impl/LoaderManager.java b/src/main/java/io/vertx/core/impl/LoaderManager.java new file mode 100644 index 000000000..e3ca659c5 --- /dev/null +++ b/src/main/java/io/vertx/core/impl/LoaderManager.java @@ -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. + *
+ * For Java 11 and above, the JVM uses a no-op implementation thanks to Multi-Release Jar. + */ +class LoaderManager { + + private final Map classLoaders = new HashMap<>(); + + /** + * IMPORTANT - 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 urls = new ArrayList<>(); + // Add any extra URLs to the beginning of the classpath + List 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()); + } +} diff --git a/src/main/java/io/vertx/core/impl/VerticleManager.java b/src/main/java/io/vertx/core/impl/VerticleManager.java index 71f8fd3b2..0fb81030b 100644 --- a/src/main/java/io/vertx/core/impl/VerticleManager.java +++ b/src/main/java/io/vertx/core/impl/VerticleManager.java @@ -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 classloaders = new HashMap<>(); + private final LoaderManager loaderManager = new LoaderManager(); private final Map> verticleFactories = new ConcurrentHashMap<>(); private final List defaultFactories = new ArrayList<>(); @@ -152,8 +145,23 @@ public class VerticleManager { public Future 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 = 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 doDeployVerticle(String identifier, @@ -204,88 +212,14 @@ public class VerticleManager { } catch (Exception e) { return Future.failedFuture(e); } - Future 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)); } - /** - * IMPORTANT - 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 urls = new ArrayList<>(); - // Add any extra URLs to the beginning of the classpath - List 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; } diff --git a/src/main/java11/io/vertx/core/DeploymentOptions.java b/src/main/java11/io/vertx/core/DeploymentOptions.java new file mode 100644 index 000000000..d50949891 --- /dev/null +++ b/src/main/java11/io/vertx/core/DeploymentOptions.java @@ -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. + *

+ * + * + * @author Tim Fox + */ +@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. + *

+ * 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}. + *

+ * Vert.x will automatically log a warning if it detects that worker threads haven't returned within this time. + *

+ * 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}. + *

+ * 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; + } +} diff --git a/src/main/java11/io/vertx/core/impl/LoaderManager.java b/src/main/java11/io/vertx/core/impl/LoaderManager.java new file mode 100644 index 000000000..caaa617d0 --- /dev/null +++ b/src/main/java11/io/vertx/core/impl/LoaderManager.java @@ -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) { + } +} diff --git a/src/test/java/io/vertx/core/DeploymentTest.java b/src/test/java/io/vertx/core/DeploymentTest.java index 75f827cf4..d9b42c527 100644 --- a/src/test/java/io/vertx/core/DeploymentTest.java +++ b/src/test/java/io/vertx/core/DeploymentTest.java @@ -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 cp = Arrays.asList("foo", "bar"); List 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 cp = Arrays.asList("foo", "bar"); List 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());