From 8d8beb5e9b37e2ba9e829e14d044ffb6f884dcbb Mon Sep 17 00:00:00 2001 From: Yeikel Date: Wed, 14 Jun 2023 04:25:10 -0400 Subject: [PATCH 001/264] Update `isAlpnAvailable` method (#4740) --- src/main/java/io/vertx/core/net/OpenSSLEngineOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/vertx/core/net/OpenSSLEngineOptions.java b/src/main/java/io/vertx/core/net/OpenSSLEngineOptions.java index 5d2c88e6ab9..44335c7d26a 100644 --- a/src/main/java/io/vertx/core/net/OpenSSLEngineOptions.java +++ b/src/main/java/io/vertx/core/net/OpenSSLEngineOptions.java @@ -37,7 +37,7 @@ public static boolean isAvailable() { * @return when alpn support is available via OpenSSL engine */ public static boolean isAlpnAvailable() { - return OpenSsl.isAlpnSupported(); + return SslProvider.isAlpnSupported(SslProvider.OPENSSL); } /** From 6f47150fa51e4a5a774df11a2efe24fc3b0f5702 Mon Sep 17 00:00:00 2001 From: Thomas Segismont Date: Wed, 14 Jun 2023 15:12:15 +0200 Subject: [PATCH 002/264] Removed deprecated Logger and LoggerFactory (#4737) * Removed deprecated Logger and LoggerFactory Also, removed unused "fatal" and templated logging methods from LogDelegate SPI. Signed-off-by: Thomas Segismont * Simplify log delegates Since parameterized methods are no longer supported (not portable) Signed-off-by: Thomas Segismont * Fix Log4J2LogDelegateTest failure In the call stack, the last FQCN before user code is the LoggerAdapter. Signed-off-by: Thomas Segismont * Fix SLF4JLogDelegateTest A couple of tests did not do what their name says. Signed-off-by: Thomas Segismont --------- Signed-off-by: Thomas Segismont --- src/main/asciidoc/index.adoc | 1 - .../core/impl/logging/LoggerAdapter.java | 7 +- .../core/impl/logging/LoggerFactory.java | 58 ++- .../io/vertx/core/logging/JULLogDelegate.java | 70 +-- .../core/logging/JULLogDelegateFactory.java | 1 + .../vertx/core/logging/Log4j2LogDelegate.java | 66 +-- .../logging/Log4j2LogDelegateFactory.java | 1 + .../java/io/vertx/core/logging/Logger.java | 287 ----------- .../io/vertx/core/logging/LoggerFactory.java | 115 ----- .../vertx/core/logging/SLF4JLogDelegate.java | 152 +----- .../core/logging/SLF4JLogDelegateFactory.java | 1 + .../vertx/core/spi/logging/LogDelegate.java | 24 - .../logging/LoggingBackendSelectionTest.java | 2 +- .../NoExceptionInInitializerErrorTest.java | 3 +- .../vertx/core/logging/LoggerFactoryTest.java | 1 + .../java/io/vertx/it/JULLogDelegateTest.java | 122 +---- .../io/vertx/it/Log4J2LogDelegateTest.java | 109 +---- .../io/vertx/it/SLF4JLogDelegateTest.java | 444 +++++++++++++----- .../java/io/vertx/it/SLF4JNoImplTest.java | 19 +- 19 files changed, 425 insertions(+), 1058 deletions(-) delete mode 100644 src/main/java/io/vertx/core/logging/Logger.java delete mode 100644 src/main/java/io/vertx/core/logging/LoggerFactory.java diff --git a/src/main/asciidoc/index.adoc b/src/main/asciidoc/index.adoc index 317f360c805..e7df5bdc9d6 100644 --- a/src/main/asciidoc/index.adoc +++ b/src/main/asciidoc/index.adoc @@ -1025,7 +1025,6 @@ The logging backend is selected as follows: . JDK logging when a `vertx-default-jul-logging.properties` file is in the classpath or, . a backend present in the classpath, in the following order of preference: .. SLF4J -.. Log4J .. Log4J2 Otherwise Vert.x defaults to JDK logging. diff --git a/src/main/java/io/vertx/core/impl/logging/LoggerAdapter.java b/src/main/java/io/vertx/core/impl/logging/LoggerAdapter.java index 5f0d2ab32cc..88b12e7508e 100644 --- a/src/main/java/io/vertx/core/impl/logging/LoggerAdapter.java +++ b/src/main/java/io/vertx/core/impl/logging/LoggerAdapter.java @@ -20,7 +20,8 @@ public final class LoggerAdapter implements Logger { private final LogDelegate adapted; - LoggerAdapter(LogDelegate adapted) { + // Visible for testing + public LoggerAdapter(LogDelegate adapted) { this.adapted = adapted; } @@ -93,4 +94,8 @@ public void error(Object message) { public void error(Object message, Throwable t) { adapted.error(message, t); } + + public LogDelegate unwrap() { + return adapted; + } } diff --git a/src/main/java/io/vertx/core/impl/logging/LoggerFactory.java b/src/main/java/io/vertx/core/impl/logging/LoggerFactory.java index 5ba32154fca..03d49530041 100644 --- a/src/main/java/io/vertx/core/impl/logging/LoggerFactory.java +++ b/src/main/java/io/vertx/core/impl/logging/LoggerFactory.java @@ -11,25 +11,77 @@ package io.vertx.core.impl.logging; +import io.vertx.core.logging.JULLogDelegateFactory; +import io.vertx.core.spi.logging.LogDelegate; +import io.vertx.core.spi.logging.LogDelegateFactory; + /** * For internal logging purposes only. * * @author Thomas Segismont */ -@SuppressWarnings("deprecation") public class LoggerFactory { + public static final String LOGGER_DELEGATE_FACTORY_CLASS_NAME = "vertx.logger-delegate-factory-class-name"; + + private static volatile LogDelegateFactory delegateFactory; + + static { + initialise(); + // Do not log before being fully initialized (a logger extension may use Vert.x classes) + LogDelegate log = delegateFactory.createDelegate(LoggerFactory.class.getName()); + log.debug("Using " + delegateFactory.getClass().getName()); + } + + private static synchronized void initialise() { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + String className; + try { + className = System.getProperty(LOGGER_DELEGATE_FACTORY_CLASS_NAME); + } catch (Exception ignore) { + className = null; + } + if (className != null && configureWith(className, false, loader)) { + return; + } + if (loader.getResource("vertx-default-jul-logging.properties") == null) { + if (configureWith("SLF4J", true, loader) + || configureWith("Log4j2", true, loader)) { + return; + } + } + // Do not use dynamic classloading here to ensure the class is visible by AOT compilers + delegateFactory = new JULLogDelegateFactory(); + } + + private static boolean configureWith(String name, boolean shortName, ClassLoader loader) { + try { + Class clazz = Class.forName(shortName ? "io.vertx.core.logging." + name + "LogDelegateFactory" : name, true, loader); + LogDelegateFactory factory = (LogDelegateFactory) clazz.getDeclaredConstructor().newInstance(); + if (!factory.isAvailable()) { + return false; + } + delegateFactory = factory; + return true; + } catch (Throwable ignore) { + return false; + } + } + /** * Like {@link #getLogger(String)}, using the provided {@code clazz} name. */ public static Logger getLogger(Class clazz) { - return new LoggerAdapter(io.vertx.core.logging.LoggerFactory.getLogger(clazz).getDelegate()); + String name = clazz.isAnonymousClass() ? + clazz.getEnclosingClass().getCanonicalName() : + clazz.getCanonicalName(); + return getLogger(name); } /** * Get the logger with the specified {@code name}. */ public static Logger getLogger(String name) { - return new LoggerAdapter(io.vertx.core.logging.LoggerFactory.getLogger(name).getDelegate()); + return new LoggerAdapter(delegateFactory.createDelegate(name)); } } diff --git a/src/main/java/io/vertx/core/logging/JULLogDelegate.java b/src/main/java/io/vertx/core/logging/JULLogDelegate.java index 5d336da2d86..aef71243cdd 100644 --- a/src/main/java/io/vertx/core/logging/JULLogDelegate.java +++ b/src/main/java/io/vertx/core/logging/JULLogDelegate.java @@ -45,109 +45,51 @@ public boolean isTraceEnabled() { return logger.isLoggable(Level.FINEST); } - public void fatal(final Object message) { - log(Level.SEVERE, message); - } - - public void fatal(final Object message, final Throwable t) { - log(Level.SEVERE, message, t); - } - public void error(final Object message) { log(Level.SEVERE, message); } - @Override - public void error(Object message, Object... params) { - log(Level.SEVERE, message, null, params); - } - public void error(final Object message, final Throwable t) { log(Level.SEVERE, message, t); } - @Override - public void error(Object message, Throwable t, Object... params) { - log(Level.SEVERE, message, t, params); - } - public void warn(final Object message) { log(Level.WARNING, message); } - @Override - public void warn(Object message, Object... params) { - log(Level.WARNING, message, null, params); - } - public void warn(final Object message, final Throwable t) { log(Level.WARNING, message, t); } - @Override - public void warn(Object message, Throwable t, Object... params) { - log(Level.WARNING, message, t, params); - } - public void info(final Object message) { log(Level.INFO, message); } - @Override - public void info(Object message, Object... params) { - log(Level.INFO, message, null, params); - } - public void info(final Object message, final Throwable t) { log(Level.INFO, message, t); } - @Override - public void info(Object message, Throwable t, Object... params) { - log(Level.INFO, message, t, params); - } - public void debug(final Object message) { log(Level.FINE, message); } - @Override - public void debug(Object message, Object... params) { - log(Level.FINE, message, null, params); - } - public void debug(final Object message, final Throwable t) { log(Level.FINE, message, t); } - @Override - public void debug(Object message, Throwable t, Object... params) { - log(Level.FINE, message, t, params); - } - public void trace(final Object message) { log(Level.FINEST, message); } - @Override - public void trace(Object message, Object... params) { - log(Level.FINEST, message, null, params); - } - public void trace(final Object message, final Throwable t) { log(Level.FINEST, message, t); } - @Override - public void trace(Object message, Throwable t, Object... params) { - log(Level.FINEST, message, t, params); - } - private void log(Level level, Object message) { log(level, message, null); } - private void log(Level level, Object message, Throwable t, Object... params) { + private void log(Level level, Object message, Throwable t) { if (!logger.isLoggable(level)) { return; } @@ -156,21 +98,13 @@ private void log(Level level, Object message, Throwable t, Object... params) { record.setLoggerName(logger.getName()); if (t != null) { record.setThrown(t); - } else if (params != null && params.length != 0 && params[params.length - 1] instanceof Throwable) { - // The exception may be the last parameters (SLF4J uses this convention). - record.setThrown((Throwable) params[params.length - 1]); } // This will disable stack trace lookup inside JUL. If someone wants location info, they can use their own formatter - // or use a different logging framework like sl4j, or log4j + // or use a different logging framework like slf4j, or log4j record.setSourceClassName(null); - record.setParameters(params); logger.log(record); } - private void log(Level level, Object message, Throwable t) { - log(level, message, t, (Object[]) null); - } - @Override public Object unwrap() { return logger; diff --git a/src/main/java/io/vertx/core/logging/JULLogDelegateFactory.java b/src/main/java/io/vertx/core/logging/JULLogDelegateFactory.java index 06a636e7fb3..b5da44f7f91 100644 --- a/src/main/java/io/vertx/core/logging/JULLogDelegateFactory.java +++ b/src/main/java/io/vertx/core/logging/JULLogDelegateFactory.java @@ -47,6 +47,7 @@ public boolean isAvailable() { return true; } + @Override public LogDelegate createDelegate(final String name) { return new JULLogDelegate(name); } diff --git a/src/main/java/io/vertx/core/logging/Log4j2LogDelegate.java b/src/main/java/io/vertx/core/logging/Log4j2LogDelegate.java index fd439f0be55..9c24a73893d 100644 --- a/src/main/java/io/vertx/core/logging/Log4j2LogDelegate.java +++ b/src/main/java/io/vertx/core/logging/Log4j2LogDelegate.java @@ -11,9 +11,9 @@ package io.vertx.core.logging; +import io.vertx.core.impl.logging.LoggerAdapter; import io.vertx.core.spi.logging.LogDelegate; import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.message.FormattedMessage; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.spi.ExtendedLogger; @@ -26,8 +26,7 @@ public class Log4j2LogDelegate implements LogDelegate { final ExtendedLogger logger; - @SuppressWarnings("deprecation") - final static String FQCN = Logger.class.getCanonicalName(); + private static final String FQCN = LoggerAdapter.class.getCanonicalName(); Log4j2LogDelegate(final String name) { logger = (ExtendedLogger) org.apache.logging.log4j.LogManager.getLogger(name); @@ -38,116 +37,71 @@ public boolean isWarnEnabled() { return logger.isWarnEnabled(); } + @Override public boolean isInfoEnabled() { return logger.isInfoEnabled(); } + @Override public boolean isDebugEnabled() { return logger.isDebugEnabled(); } + @Override public boolean isTraceEnabled() { return logger.isTraceEnabled(); } - public void fatal(final Object message) { - log(Level.FATAL, message); - } - - public void fatal(final Object message, final Throwable t) { - log(Level.FATAL, message, t); - } - + @Override public void error(final Object message) { log(Level.ERROR, message); } @Override - public void error(Object message, Object... params) { - log(Level.ERROR, message.toString(), params); - } - public void error(final Object message, final Throwable t) { log(Level.ERROR, message, t); } @Override - public void error(Object message, Throwable t, Object... params) { - log(Level.ERROR, message.toString(), t, params); - } - public void warn(final Object message) { log(Level.WARN, message); } @Override - public void warn(Object message, Object... params) { - log(Level.WARN, message.toString(), params); - } - public void warn(final Object message, final Throwable t) { log(Level.WARN, message, t); } @Override - public void warn(Object message, Throwable t, Object... params) { - log(Level.WARN, message.toString(), t, params); - } - public void info(final Object message) { log(Level.INFO, message); } @Override - public void info(Object message, Object... params) { - log(Level.INFO, message.toString(), params); - } - public void info(final Object message, final Throwable t) { log(Level.INFO, message, t); } @Override - public void info(Object message, Throwable t, Object... params) { - log(Level.INFO, message.toString(), t, params); - } - public void debug(final Object message) { log(Level.DEBUG, message); } @Override - public void debug(Object message, Object... params) { - log(Level.DEBUG, message.toString(), params); - } - public void debug(final Object message, final Throwable t) { log(Level.DEBUG, message, t); } @Override - public void debug(Object message, Throwable t, Object... params) { - log(Level.DEBUG, message.toString(), t, params); - } - public void trace(final Object message) { log(Level.TRACE, message); } @Override - public void trace(Object message, Object... params) { - log(Level.TRACE, message.toString(), params); - } - public void trace(final Object message, final Throwable t) { log(Level.TRACE, message.toString(), t); } - @Override - public void trace(Object message, Throwable t, Object... params) { - log(Level.TRACE, message.toString(), t, params); - } - private void log(Level level, Object message) { log(level, message, null); } @@ -160,14 +114,6 @@ private void log(Level level, Object message, Throwable t) { } } - private void log(Level level, String message, Object... params) { - logger.logIfEnabled(FQCN, level, null, message, params); - } - - private void log(Level level, String message, Throwable t, Object... params) { - logger.logIfEnabled(FQCN, level, null, new FormattedMessage(message, params), t); - } - @Override public Object unwrap() { return logger; diff --git a/src/main/java/io/vertx/core/logging/Log4j2LogDelegateFactory.java b/src/main/java/io/vertx/core/logging/Log4j2LogDelegateFactory.java index 68d525f7268..fd12351b2d3 100644 --- a/src/main/java/io/vertx/core/logging/Log4j2LogDelegateFactory.java +++ b/src/main/java/io/vertx/core/logging/Log4j2LogDelegateFactory.java @@ -27,6 +27,7 @@ public boolean isAvailable() { return LogManager.getLogger(Log4j2LogDelegateFactory.class) != null; } + @Override public LogDelegate createDelegate(final String name) { return new Log4j2LogDelegate(name); } diff --git a/src/main/java/io/vertx/core/logging/Logger.java b/src/main/java/io/vertx/core/logging/Logger.java deleted file mode 100644 index cbb5fac0334..00000000000 --- a/src/main/java/io/vertx/core/logging/Logger.java +++ /dev/null @@ -1,287 +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.logging; - -import io.vertx.core.spi.logging.LogDelegate; - -/** - * This class allows us to isolate all our logging dependencies in one place. It also allows us to have zero runtime - * 3rd party logging jar dependencies, since we default to JUL by default. - *

- * By default logging will occur using JUL (Java-Util-Logging). The logging configuration file (logging.properties) - * used by JUL will taken from the default logging.properties in the JDK installation if no {@code java.util.logging.config.file} system - * property is set. - *

- * If you would prefer to use Log4J 2 or SLF4J instead of JUL then you can set a system property called - * {@code vertx.logger-delegate-factory-class-name} to the class name of the delegate for your logging system. - * For Log4J 2 the value is {@link io.vertx.core.logging.Log4j2LogDelegateFactory}, for SLF4J the value - * is {@link io.vertx.core.logging.SLF4JLogDelegateFactory}. You will need to ensure whatever jar files - * required by your favourite log framework are on your classpath. - *

- * Keep in mind that logging backends use different formats to represent replaceable tokens in parameterized messages. - * As a consequence, if you rely on parameterized logging methods, you won't be able to switch backends without changing your code. - * - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - * - * @author Tim Fox - */ -@Deprecated -public class Logger { - - final LogDelegate delegate; - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public Logger(final LogDelegate delegate) { - this.delegate = delegate; - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public boolean isWarnEnabled() { - return delegate.isWarnEnabled(); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public boolean isInfoEnabled() { - return delegate.isInfoEnabled(); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public boolean isDebugEnabled() { - return delegate.isDebugEnabled(); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public boolean isTraceEnabled() { - return delegate.isTraceEnabled(); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void fatal(final Object message) { - delegate.fatal(message); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void fatal(final Object message, final Throwable t) { - delegate.fatal(message, t); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void error(final Object message) { - delegate.error(message); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void error(final Object message, final Throwable t) { - delegate.error(message, t); - } - - /** - * @throws UnsupportedOperationException if the logging backend does not support parameterized messages - * - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void error(final Object message, final Object... objects) { - delegate.error(message, objects); - } - - /** - * @throws UnsupportedOperationException if the logging backend does not support parameterized messages - * - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void error(final Object message, final Throwable t, final Object... objects) { - delegate.error(message, t, objects); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void warn(final Object message) { - delegate.warn(message); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void warn(final Object message, final Throwable t) { - delegate.warn(message, t); - } - - /** - * @throws UnsupportedOperationException if the logging backend does not support parameterized messages - * - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void warn(final Object message, final Object... objects) { - delegate.warn(message, objects); - } - - /** - * @throws UnsupportedOperationException if the logging backend does not support parameterized messages - * - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void warn(final Object message, final Throwable t, final Object... objects) { - delegate.warn(message, t, objects); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void info(final Object message) { - delegate.info(message); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void info(final Object message, final Throwable t) { - delegate.info(message, t); - } - - /** - * @throws UnsupportedOperationException if the logging backend does not support parameterized messages - * - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void info(final Object message, final Object... objects) { - delegate.info(message, objects); - } - - /** - * @throws UnsupportedOperationException if the logging backend does not support parameterized messages - * - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void info(final Object message, final Throwable t, final Object... objects) { - delegate.info(message, t, objects); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void debug(final Object message) { - delegate.debug(message); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void debug(final Object message, final Throwable t) { - delegate.debug(message, t); - } - - /** - * @throws UnsupportedOperationException if the logging backend does not support parameterized messages - * - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void debug(final Object message, final Object... objects) { - delegate.debug(message, objects); - } - - /** - * @throws UnsupportedOperationException if the logging backend does not support parameterized messages - * - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void debug(final Object message, final Throwable t, final Object... objects) { - delegate.debug(message, t, objects); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void trace(final Object message) { - delegate.trace(message); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void trace(final Object message, final Throwable t) { - delegate.trace(message, t); - } - - /** - * @throws UnsupportedOperationException if the logging backend does not support parameterized messages - * - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void trace(final Object message, final Object... objects) { - delegate.trace(message, objects); - } - - /** - * @throws UnsupportedOperationException if the logging backend does not support parameterized messages - * - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public void trace(final Object message, final Throwable t, final Object... objects) { - delegate.trace(message, t, objects); - } - - /** - * @return the delegate instance sending operations to the underlying logging framework - * - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public LogDelegate getDelegate() { - return delegate; - } -} diff --git a/src/main/java/io/vertx/core/logging/LoggerFactory.java b/src/main/java/io/vertx/core/logging/LoggerFactory.java deleted file mode 100644 index 7cf843ca7da..00000000000 --- a/src/main/java/io/vertx/core/logging/LoggerFactory.java +++ /dev/null @@ -1,115 +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.logging; - -import io.vertx.core.spi.logging.LogDelegate; -import io.vertx.core.spi.logging.LogDelegateFactory; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - * - * @author Tim Fox - */ -public class LoggerFactory { - - public static final String LOGGER_DELEGATE_FACTORY_CLASS_NAME = "vertx.logger-delegate-factory-class-name"; - - private static volatile LogDelegateFactory delegateFactory; - - private static final ConcurrentMap loggers = new ConcurrentHashMap<>(); - - static { - initialise(); - // Do not log before being fully initialized (a logger extension may use Vert.x classes) - LogDelegate log = delegateFactory.createDelegate(LoggerFactory.class.getName()); - log.debug("Using " + delegateFactory.getClass().getName()); - } - - public static synchronized void initialise() { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - String className; - try { - className = System.getProperty(LOGGER_DELEGATE_FACTORY_CLASS_NAME); - } catch (Exception ignore) { - className = null; - } - if (className != null && configureWith(className, false, loader)) { - return; - } - if (loader.getResource("vertx-default-jul-logging.properties") == null) { - if (configureWith("SLF4J", true, loader) - || configureWith("Log4j2", true, loader)) { - return; - } - } - // Do not use dynamic classloading here to ensure the class is visible by AOT compilers - delegateFactory = new JULLogDelegateFactory(); - } - - private static boolean configureWith(String name, boolean shortName, ClassLoader loader) { - try { - Class clazz = Class.forName(shortName ? "io.vertx.core.logging." + name + "LogDelegateFactory" : name, true, loader); - LogDelegateFactory factory = (LogDelegateFactory) clazz.getDeclaredConstructor().newInstance(); - if (!factory.isAvailable()) { - return false; - } - delegateFactory = factory; - return true; - } catch (Throwable ignore) { - return false; - } - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public static Logger getLogger(final Class clazz) { - String name = clazz.isAnonymousClass() ? - clazz.getEnclosingClass().getCanonicalName() : - clazz.getCanonicalName(); - return getLogger(name); - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public static Logger getLogger(final String name) { - Logger logger = loggers.get(name); - - if (logger == null) { - LogDelegate delegate = delegateFactory.createDelegate(name); - - logger = new Logger(delegate); - - Logger oldLogger = loggers.putIfAbsent(name, logger); - - if (oldLogger != null) { - logger = oldLogger; - } - } - - return logger; - } - - /** - * @deprecated see https://github.com/eclipse-vertx/vert.x/issues/2774 - */ - @Deprecated - public static void removeLogger(String name) { - loggers.remove(name); - } -} diff --git a/src/main/java/io/vertx/core/logging/SLF4JLogDelegate.java b/src/main/java/io/vertx/core/logging/SLF4JLogDelegate.java index a475aba5d45..afbf3ce1e4e 100644 --- a/src/main/java/io/vertx/core/logging/SLF4JLogDelegate.java +++ b/src/main/java/io/vertx/core/logging/SLF4JLogDelegate.java @@ -15,28 +15,19 @@ import io.vertx.core.spi.logging.LogDelegate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.slf4j.helpers.FormattingTuple; -import org.slf4j.helpers.MessageFormatter; -import org.slf4j.spi.LocationAwareLogger; - -import static org.slf4j.spi.LocationAwareLogger.*; /** * @author Tim Fox */ public class SLF4JLogDelegate implements LogDelegate { - private static final Object[] EMPTY_PARAMETERS = {}; - - @SuppressWarnings("deprecation") - private static final String FQCN = io.vertx.core.logging.Logger.class.getCanonicalName(); - private final Logger logger; SLF4JLogDelegate(final String name) { logger = LoggerFactory.getLogger(name); } + // Visible for testing public SLF4JLogDelegate(Object logger) { this.logger = (Logger) logger; } @@ -46,178 +37,73 @@ public boolean isWarnEnabled() { return logger.isWarnEnabled(); } + @Override public boolean isInfoEnabled() { return logger.isInfoEnabled(); } + @Override public boolean isDebugEnabled() { return logger.isDebugEnabled(); } + @Override public boolean isTraceEnabled() { return logger.isTraceEnabled(); } - public void fatal(final Object message) { - log(ERROR_INT, message); - } - - public void fatal(final Object message, final Throwable t) { - log(ERROR_INT, message, t); - } - + @Override public void error(final Object message) { - log(ERROR_INT, message); + logger.error(valueOf(message)); } @Override - public void error(Object message, Object... params) { - log(ERROR_INT, message, null, params); - } - public void error(final Object message, final Throwable t) { - log(ERROR_INT, message, t); + logger.error(valueOf(message), t); } @Override - public void error(Object message, Throwable t, Object... params) { - log(ERROR_INT, message, t, params); - } - public void warn(final Object message) { - log(WARN_INT, message); + logger.warn(valueOf(message)); } @Override - public void warn(Object message, Object... params) { - log(WARN_INT, message, null, params); - } - public void warn(final Object message, final Throwable t) { - log(WARN_INT, message, t); + logger.warn(valueOf(message), t); } @Override - public void warn(Object message, Throwable t, Object... params) { - log(WARN_INT, message, t, params); - } - public void info(final Object message) { - log(INFO_INT, message); + logger.info(valueOf(message)); } @Override - public void info(Object message, Object... params) { - log(INFO_INT, message, null, params); - } - public void info(final Object message, final Throwable t) { - log(INFO_INT, message, t); + logger.info(valueOf(message), t); } @Override - public void info(Object message, Throwable t, Object... params) { - log(INFO_INT, message, t, params); - } - public void debug(final Object message) { - log(DEBUG_INT, message); - } - - public void debug(final Object message, final Object... params) { - log(DEBUG_INT, message, null, params); + logger.debug(valueOf(message)); } + @Override public void debug(final Object message, final Throwable t) { - log(DEBUG_INT, message, t); - } - - public void debug(final Object message, final Throwable t, final Object... params) { - log(DEBUG_INT, message, t, params); + logger.debug(valueOf(message), t); } + @Override public void trace(final Object message) { - log(TRACE_INT, message); + logger.trace(valueOf(message)); } @Override - public void trace(Object message, Object... params) { - log(TRACE_INT, message, null, params); - } - public void trace(final Object message, final Throwable t) { - log(TRACE_INT, message, t); + logger.trace(valueOf(message), t); } - @Override - public void trace(Object message, Throwable t, Object... params) { - log(TRACE_INT, message, t, params); - } - - private void log(int level, Object message) { - log(level, message, null); - } - - private void log(int level, Object message, Throwable t) { - log(level, message, t, (Object[]) null); - } - - private void log(int level, Object message, Throwable t, Object... params) { - String msg = (message == null) ? "NULL" : message.toString(); - - // We need to compute the right parameters. - // If we have both parameters and an error, we need to build a new array [params, t] - // If we don't have parameters, we need to build a new array [t] - // If we don't have error, it's just params. - Object[] parameters; - if (params == null) { - if (t == null) { - parameters = EMPTY_PARAMETERS; - } else { - parameters = new Object[]{t}; - } - } else { - if (t == null) { - parameters = params; - } else { - parameters = new Object[params.length + 1]; - System.arraycopy(params, 0, parameters, 0, params.length); - parameters[params.length] = t; - } - } - - if (logger instanceof LocationAwareLogger) { - // make sure we don't format the objects if we don't log the line anyway - if (level == TRACE_INT && logger.isTraceEnabled() || - level == DEBUG_INT && logger.isDebugEnabled() || - level == INFO_INT && logger.isInfoEnabled() || - level == WARN_INT && logger.isWarnEnabled() || - level == ERROR_INT && logger.isErrorEnabled()) { - LocationAwareLogger l = (LocationAwareLogger) logger; - FormattingTuple ft = MessageFormatter.arrayFormat(msg, parameters); - l.log(null, FQCN, level, ft.getMessage(), null, ft.getThrowable()); - } - } else { - switch (level) { - case TRACE_INT: - logger.trace(msg, parameters); - break; - case DEBUG_INT: - logger.debug(msg, parameters); - break; - case INFO_INT: - logger.info(msg, parameters); - break; - case WARN_INT: - logger.warn(msg, parameters); - break; - case ERROR_INT: - logger.error(msg, parameters); - break; - default: - throw new IllegalArgumentException("Unknown log level " + level); - } - } + private static String valueOf(Object message) { + return message == null ? "NULL" : message.toString(); } @Override diff --git a/src/main/java/io/vertx/core/logging/SLF4JLogDelegateFactory.java b/src/main/java/io/vertx/core/logging/SLF4JLogDelegateFactory.java index 65a091331e9..071728a7fd2 100644 --- a/src/main/java/io/vertx/core/logging/SLF4JLogDelegateFactory.java +++ b/src/main/java/io/vertx/core/logging/SLF4JLogDelegateFactory.java @@ -45,6 +45,7 @@ public boolean isAvailable() { return !(fact instanceof NOPLoggerFactory); } + @Override public LogDelegate createDelegate(final String clazz) { return new SLF4JLogDelegate(clazz); } diff --git a/src/main/java/io/vertx/core/spi/logging/LogDelegate.java b/src/main/java/io/vertx/core/spi/logging/LogDelegate.java index c399383430a..fa62f98ffc4 100644 --- a/src/main/java/io/vertx/core/spi/logging/LogDelegate.java +++ b/src/main/java/io/vertx/core/spi/logging/LogDelegate.java @@ -26,50 +26,26 @@ public interface LogDelegate { boolean isTraceEnabled(); - void fatal(Object message); - - void fatal(Object message, Throwable t); - void error(Object message); - void error(Object message, Object... params); - void error(Object message, Throwable t); - void error(Object message, Throwable t, Object... params); - void warn(Object message); - void warn(Object message, Object... params); - void warn(Object message, Throwable t); - void warn(Object message, Throwable t, Object... params); - void info(Object message); - void info(Object message, Object... params); - void info(Object message, Throwable t); - void info(Object message, Throwable t, Object... params); - void debug(Object message); - void debug(Object message, Object... params); - void debug(Object message, Throwable t); - void debug(Object message, Throwable t, Object... params); - void trace(Object message); - void trace(Object message, Object... params); - void trace(Object message, Throwable t); - void trace(Object message, Throwable t, Object... params); - /** * @return the underlying framework logger object, null in the default implementation */ diff --git a/src/test/java/io/vertx/core/impl/logging/LoggingBackendSelectionTest.java b/src/test/java/io/vertx/core/impl/logging/LoggingBackendSelectionTest.java index 3569125698e..89f8ee62497 100644 --- a/src/test/java/io/vertx/core/impl/logging/LoggingBackendSelectionTest.java +++ b/src/test/java/io/vertx/core/impl/logging/LoggingBackendSelectionTest.java @@ -24,7 +24,7 @@ import java.util.HashSet; import java.util.Set; -import static io.vertx.core.logging.LoggerFactory.LOGGER_DELEGATE_FACTORY_CLASS_NAME; +import static io.vertx.core.impl.logging.LoggerFactory.LOGGER_DELEGATE_FACTORY_CLASS_NAME; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/io/vertx/core/impl/logging/NoExceptionInInitializerErrorTest.java b/src/test/java/io/vertx/core/impl/logging/NoExceptionInInitializerErrorTest.java index 20a18f092e7..0db8809a3a4 100644 --- a/src/test/java/io/vertx/core/impl/logging/NoExceptionInInitializerErrorTest.java +++ b/src/test/java/io/vertx/core/impl/logging/NoExceptionInInitializerErrorTest.java @@ -20,8 +20,7 @@ import org.junit.After; import org.junit.Test; -import static io.vertx.core.logging.LoggerFactory.LOGGER_DELEGATE_FACTORY_CLASS_NAME; - +import static io.vertx.core.impl.logging.LoggerFactory.LOGGER_DELEGATE_FACTORY_CLASS_NAME; /** * Must be separated from {@link LoggingBackendSelectionTest}. diff --git a/src/test/java/io/vertx/core/logging/LoggerFactoryTest.java b/src/test/java/io/vertx/core/logging/LoggerFactoryTest.java index 6fabefa4b06..75370b3bcb8 100644 --- a/src/test/java/io/vertx/core/logging/LoggerFactoryTest.java +++ b/src/test/java/io/vertx/core/logging/LoggerFactoryTest.java @@ -11,6 +11,7 @@ package io.vertx.core.logging; +import io.vertx.core.impl.logging.LoggerFactory; import org.junit.Test; /** diff --git a/src/test/java/io/vertx/it/JULLogDelegateTest.java b/src/test/java/io/vertx/it/JULLogDelegateTest.java index bb672b60d37..15d2c6920fe 100644 --- a/src/test/java/io/vertx/it/JULLogDelegateTest.java +++ b/src/test/java/io/vertx/it/JULLogDelegateTest.java @@ -11,8 +11,9 @@ package io.vertx.it; -import io.vertx.core.logging.Logger; -import io.vertx.core.logging.LoggerFactory; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerAdapter; +import io.vertx.core.impl.logging.LoggerFactory; import io.vertx.core.spi.logging.LogDelegate; import org.junit.BeforeClass; import org.junit.Test; @@ -27,7 +28,6 @@ * * @author Clement Escoffier */ -@SuppressWarnings("deprecation") public class JULLogDelegateTest { private static Logger logger; @@ -42,7 +42,7 @@ public static void initialize() throws IOException { @Test public void testDelegateUnwrap() { - LogDelegate delegate = logger.getDelegate(); + LogDelegate delegate = ((LoggerAdapter) logger).unwrap(); assertNotNull("Delegate is null", delegate); try { java.util.logging.Logger unwrapped = (java.util.logging.Logger) delegate.unwrap(); @@ -66,44 +66,6 @@ public void testInfo() { assertTrue(result.contains("exception")); assertTrue(result.contains("java.lang.NullPointerException")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.info("hello {0} and {1}", "Paulo", "Julien"); - }); - assertTrue(result.contains("hello Paulo and Julien")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.info("hello {0}", "vert.x"); - }); - assertTrue(result.contains("hello vert.x")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.info("hello {0} - {1}", "vert.x"); - }); - assertTrue(result.contains("hello vert.x - {1}")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.info("hello {0}", "vert.x", "foo"); - }); - assertTrue(result.contains("hello vert.x")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.info("{0}, an exception has been thrown", new IllegalStateException(), "Luke"); - }); - assertTrue(result.contains("Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.info("{0}, an exception has been thrown", "Luke", new IllegalStateException()); - }); - assertTrue(result.contains("Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); } @Test @@ -119,44 +81,6 @@ public void testError() { }); assertTrue(result.contains("exception")); assertTrue(result.contains("java.lang.NullPointerException")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.error("hello {0} and {1}", "Paulo", "Julien"); - }); - assertTrue(result.contains("hello Paulo and Julien")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.error("hello {0}", "vert.x"); - }); - assertTrue(result.contains("hello vert.x")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.error("hello {0} - {1}", "vert.x"); - }); - assertTrue(result.contains("hello vert.x - {1}")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.error("hello {0}", "vert.x", "foo"); - }); - assertTrue(result.contains("hello vert.x")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.error("{0}, an exception has been thrown", new IllegalStateException(), "Luke"); - }); - assertTrue(result.contains("Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.error("{0}, an exception has been thrown", "Luke", new IllegalStateException()); - }); - assertTrue(result.contains("Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); } @Test @@ -172,43 +96,5 @@ public void testWarning() { }); assertTrue(result.contains("exception")); assertTrue(result.contains("java.lang.NullPointerException")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.warn("hello {0} and {1}", "Paulo", "Julien"); - }); - assertTrue(result.contains("hello Paulo and Julien")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.warn("hello {0}", "vert.x"); - }); - assertTrue(result.contains("hello vert.x")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.warn("hello {0} - {1}", "vert.x"); - }); - assertTrue(result.contains("hello vert.x - {1}")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.warn("hello {0}", "vert.x", "foo"); - }); - assertTrue(result.contains("hello vert.x")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.warn("{0}, an exception has been thrown", new IllegalStateException(), "Luke"); - }); - assertTrue(result.contains("Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); - - result = recording.execute(() -> { - Logger logger = LoggerFactory.getLogger("my-jul-logger"); - logger.warn("{0}, an exception has been thrown", "Luke", new IllegalStateException()); - }); - assertTrue(result.contains("Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); } } diff --git a/src/test/java/io/vertx/it/Log4J2LogDelegateTest.java b/src/test/java/io/vertx/it/Log4J2LogDelegateTest.java index 0eed316af05..a78e80ecdec 100644 --- a/src/test/java/io/vertx/it/Log4J2LogDelegateTest.java +++ b/src/test/java/io/vertx/it/Log4J2LogDelegateTest.java @@ -11,8 +11,9 @@ package io.vertx.it; -import io.vertx.core.logging.Logger; -import io.vertx.core.logging.LoggerFactory; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerAdapter; +import io.vertx.core.impl.logging.LoggerFactory; import io.vertx.core.spi.logging.LogDelegate; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -23,11 +24,10 @@ import static org.junit.Assert.*; /** - * Theses test checks the Log4J 2 log delegate. + * These test checks the Log4J 2 log delegate. * * @author Clement Escoffier */ -@SuppressWarnings("deprecation") public class Log4J2LogDelegateTest { private static StreamRecording recording; @@ -45,7 +45,7 @@ public static void terminate() { @Test public void testDelegateUnwrap() { Logger logger = LoggerFactory.getLogger("my-log4j2-logger"); - LogDelegate delegate = logger.getDelegate(); + LogDelegate delegate = ((LoggerAdapter) logger).unwrap(); assertNotNull("Delegate is null", delegate); try { org.apache.logging.log4j.Logger unwrapped = (org.apache.logging.log4j.Logger) delegate.unwrap(); @@ -67,39 +67,6 @@ public void testInfo() { }); assertTrue(result.contains("exception")); assertTrue(result.contains("java.lang.NullPointerException")); - - result = recording.execute(() -> { - logger.info("hello {} and {}", "Paulo", "Julien"); - }); - assertTrue(result.contains("hello Paulo and Julien")); - - result = recording.execute(() -> { - logger.info("hello {}", "vert.x"); - }); - String expected = "hello vert.x"; - assertTrue("Was expected <" + result + "> to contain <" + expected + ">" , result.contains(expected)); - - result = recording.execute(() -> { - logger.info("hello {} - {}", "vert.x"); - }); - assertTrue(result.contains("hello vert.x - {}")); - - result = recording.execute(() -> { - logger.info("hello {} {}", "vert.x", "foo"); - }); - assertTrue(result.contains("hello vert.x foo")); - - result = recording.execute(() -> { - logger.info("{}, an exception has been thrown", new IllegalStateException(), "Luke"); - }); - assertTrue(result.contains("Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); - - result = recording.execute(() -> { - logger.info("{}, an exception has been thrown", "Luke", new IllegalStateException()); - }); - assertTrue(result.contains("Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); } @Test @@ -114,39 +81,6 @@ public void testError() { }); assertTrue(result.contains("exception")); assertTrue(result.contains("java.lang.NullPointerException")); - - result = recording.execute(() -> { - logger.error("hello {} and {}", "Paulo", "Julien"); - }); - assertTrue(result.contains("hello Paulo and Julien")); - - result = recording.execute(() -> { - logger.error("hello {}", "vert.x"); - }); - assertTrue(result.contains("hello vert.x")); - - result = recording.execute(() -> { - logger.error("hello {} - {}", "vert.x"); - }); - assertTrue(result.contains("hello vert.x - {}")); - - result = recording.execute(() -> { - logger.error("hello {} {}", "vert.x", "foo"); - }); - String expected = "hello vert.x foo"; - assertTrue("Was expected <" + result + "> to contain <" + expected + ">" , result.contains(expected)); - - result = recording.execute(() -> { - logger.error("{}, an exception has been thrown", new IllegalStateException(), "Luke"); - }); - assertTrue(result.contains("Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); - - result = recording.execute(() -> { - logger.error("{}, an exception has been thrown", "Luke", new IllegalStateException()); - }); - assertTrue(result.contains("Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); } @Test @@ -161,39 +95,6 @@ public void testWarning() { }); assertTrue(result.contains("exception")); assertTrue(result.contains("java.lang.NullPointerException")); - - result = recording.execute(() -> { - logger.warn("hello {} and {}", "Paulo", "Julien"); - }); - assertTrue(result.contains("hello Paulo and Julien")); - - result = recording.execute(() -> { - logger.warn("hello {}", "vert.x"); - }); - assertTrue(result.contains("hello vert.x")); - - result = recording.execute(() -> { - logger.warn("hello {} - {}", "vert.x"); - }); - assertTrue(result.contains("hello vert.x - {}")); - - result = recording.execute(() -> { - logger.warn("hello {} {}", "vert.x", "foo"); - }); - String expected = "hello vert.x foo"; - assertTrue("Was expected <" + result + "> to contain <" + expected + ">" , result.contains(expected)); - - result = recording.execute(() -> { - logger.warn("{}, an exception has been thrown", new IllegalStateException(), "Luke"); - }); - assertTrue(result.contains("Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); - - result = recording.execute(() -> { - logger.warn("{}, an exception has been thrown", "Luke", new IllegalStateException()); - }); - assertTrue(result.contains("Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); } // test that line numbers and method name are logged correctly diff --git a/src/test/java/io/vertx/it/SLF4JLogDelegateTest.java b/src/test/java/io/vertx/it/SLF4JLogDelegateTest.java index aac7579a59c..c88fd49bf9c 100644 --- a/src/test/java/io/vertx/it/SLF4JLogDelegateTest.java +++ b/src/test/java/io/vertx/it/SLF4JLogDelegateTest.java @@ -11,8 +11,9 @@ package io.vertx.it; -import io.vertx.core.logging.Logger; -import io.vertx.core.logging.LoggerFactory; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerAdapter; +import io.vertx.core.impl.logging.LoggerFactory; import io.vertx.core.logging.SLF4JLogDelegate; import io.vertx.core.spi.logging.LogDelegate; import org.junit.Test; @@ -28,19 +29,18 @@ import static org.junit.Assert.*; /** - * Theses test checks the SLF4J log delegate. It assumes the binding used by SLF4J is slf4j-simple with the default + * These test checks the SLF4J log delegate. It assumes the binding used by SLF4J is slf4j-simple with the default * configuration. It injects a print stream to read the logged message. This is definitely a hack, but it's the only * way to test the output. * * @author Clement Escoffier */ -@SuppressWarnings("deprecation") public class SLF4JLogDelegateTest { @Test public void testDelegateUnwrap() { Logger logger = LoggerFactory.getLogger("my-slf4j-logger"); - LogDelegate delegate = logger.getDelegate(); + LogDelegate delegate = ((LoggerAdapter) logger).unwrap(); assertNotNull("Delegate is null", delegate); try { org.slf4j.Logger unwrapped = (org.slf4j.Logger) delegate.unwrap(); @@ -57,7 +57,7 @@ public void testInfo() { @Test public void testInfoLocationAware() { - testInfo(new Logger(new SLF4JLogDelegate(new TestLocationAwareLogger("my-slf4j-logger")))); + testInfo(new LoggerAdapter(new SLF4JLogDelegate(new TestLocationAwareLogger("my-slf4j-logger")))); } private void testInfo(Logger logger) { @@ -67,26 +67,6 @@ private void testInfo(Logger logger) { result = record(() -> logger.info("exception", new NullPointerException())); assertTrue(result.contains("[main] INFO my-slf4j-logger - exception")); assertTrue(result.contains("java.lang.NullPointerException")); - - result = record(() -> logger.info("hello {} and {}", "Paulo", "Julien")); - assertContains("[main] INFO my-slf4j-logger - hello Paulo and Julien", result); - - result = record(() -> logger.info("hello {}", "vert.x")); - assertContains("[main] INFO my-slf4j-logger - hello vert.x", result); - - result = record(() -> logger.info("hello {} - {}", "vert.x")); - assertContains("[main] INFO my-slf4j-logger - hello vert.x - {}", result); - - result = record(() -> logger.info("hello {}", "vert.x", "foo")); - assertContains("[main] INFO my-slf4j-logger - hello vert.x", result); - - result = record(() -> logger.info("{}, an exception has been thrown", new IllegalStateException(), "Luke")); - assertTrue(result.contains("[main] INFO my-slf4j-logger - Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); - - result = record(() -> logger.info("{}, an exception has been thrown", "Luke", new IllegalStateException())); - assertTrue(result.contains("[main] INFO my-slf4j-logger - Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); } @Test @@ -96,7 +76,7 @@ public void testError() { @Test public void testErrorLocationAware() { - testError(LoggerFactory.getLogger("my-slf4j-logger")); + testError(new LoggerAdapter(new SLF4JLogDelegate(new TestLocationAwareLogger("my-slf4j-logger")))); } private void testError(Logger logger) { @@ -106,26 +86,6 @@ private void testError(Logger logger) { result = record(() -> logger.error("exception", new NullPointerException())); assertTrue(result.contains("[main] ERROR my-slf4j-logger - exception")); assertTrue(result.contains("java.lang.NullPointerException")); - - result = record(() -> logger.error("hello {} and {}", "Paulo", "Julien")); - assertContains("[main] ERROR my-slf4j-logger - hello Paulo and Julien", result); - - result = record(() -> logger.error("hello {}", "vert.x")); - assertContains("[main] ERROR my-slf4j-logger - hello vert.x", result); - - result = record(() -> logger.error("hello {} - {}", "vert.x")); - assertContains("[main] ERROR my-slf4j-logger - hello vert.x - {}", result); - - result = record(() -> logger.error("hello {}", "vert.x", "foo")); - assertContains("[main] ERROR my-slf4j-logger - hello vert.x", result); - - result = record(() -> logger.error("{}, an exception has been thrown", new IllegalStateException(), "Luke")); - assertTrue(result.contains("[main] ERROR my-slf4j-logger - Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); - - result = record(() -> logger.error("{}, an exception has been thrown", "Luke", new IllegalStateException())); - assertTrue(result.contains("[main] ERROR my-slf4j-logger - Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); } private void assertContains(String expectedExcerpt, String object) { @@ -140,7 +100,7 @@ public void testWarning() { @Test public void testWarningLocationAware() { - testWarning(LoggerFactory.getLogger("my-slf4j-logger")); + testWarning(new LoggerAdapter(new SLF4JLogDelegate(new TestLocationAwareLogger("my-slf4j-logger")))); } private void testWarning(Logger logger) { @@ -150,26 +110,6 @@ private void testWarning(Logger logger) { result = record(() -> logger.warn("exception", new NullPointerException())); assertTrue(result.contains("[main] WARN my-slf4j-logger - exception")); assertTrue(result.contains("java.lang.NullPointerException")); - - result = record(() -> logger.warn("hello {} and {}", "Paulo", "Julien")); - assertContains("[main] WARN my-slf4j-logger - hello Paulo and Julien", result); - - result = record(() -> logger.warn("hello {}", "vert.x")); - assertContains("[main] WARN my-slf4j-logger - hello vert.x", result); - - result = record(() -> logger.warn("hello {} - {}", "vert.x")); - assertContains("[main] WARN my-slf4j-logger - hello vert.x - {}", result); - - result = record(() -> logger.warn("hello {}", "vert.x", "foo")); - assertContains("[main] WARN my-slf4j-logger - hello vert.x", result); - - result = record(() -> logger.warn("{}, an exception has been thrown", new IllegalStateException(), "Luke")); - assertTrue(result.contains("[main] WARN my-slf4j-logger - Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); - - result = record(() -> logger.warn("{}, an exception has been thrown", "Luke", new IllegalStateException())); - assertTrue(result.contains("[main] WARN my-slf4j-logger - Luke, an exception has been thrown")); - assertTrue(result.contains("java.lang.IllegalStateException")); } private void setStream(PrintStream stream) { @@ -210,7 +150,7 @@ static class TestLocationAwareLogger implements LocationAwareLogger { TestLocationAwareLogger(String name) { Logger logger = LoggerFactory.getLogger(name); - SLF4JLogDelegate delegate = (SLF4JLogDelegate) logger.getDelegate(); + SLF4JLogDelegate delegate = (SLF4JLogDelegate) ((LoggerAdapter) logger).unwrap(); this.actual = (org.slf4j.Logger) delegate.unwrap(); } @@ -236,66 +176,310 @@ public void log(Marker marker, String fqcn, int level, String message, Object[] throw new AssertionError(); } } - @Override public String getName() { return actual.getName(); } - @Override public boolean isTraceEnabled() { return actual.isTraceEnabled(); } - @Override public void trace(String msg) { throw new AssertionError(); } - @Override public void trace(String format, Object arg) { throw new AssertionError(); } - @Override public void trace(String format, Object arg1, Object arg2) { throw new AssertionError(); } - @Override public void trace(String format, Object... arguments) { throw new AssertionError(); } - @Override public void trace(String msg, Throwable t) { actual.trace(msg, t); } - @Override public boolean isTraceEnabled(Marker marker) { return actual.isTraceEnabled(); } - @Override public void trace(Marker marker, String msg) { throw new AssertionError(); } - @Override public void trace(Marker marker, String format, Object arg) { throw new AssertionError(); } - @Override public void trace(Marker marker, String format, Object arg1, Object arg2) { actual.trace(marker, format, arg1, arg2); } - @Override public void trace(Marker marker, String format, Object... argArray) { throw new AssertionError(); } - @Override public void trace(Marker marker, String msg, Throwable t) { actual.trace(marker, msg, t); } - @Override public boolean isDebugEnabled() { return actual.isDebugEnabled(); } - @Override public void debug(String msg) { throw new AssertionError(); } - @Override public void debug(String format, Object arg) { throw new AssertionError(); } - @Override public void debug(String format, Object arg1, Object arg2) { throw new AssertionError(); } - @Override public void debug(String format, Object... arguments) { throw new AssertionError(); } - @Override public void debug(String msg, Throwable t) { throw new AssertionError(); } - @Override public boolean isDebugEnabled(Marker marker) { return actual.isDebugEnabled(marker); } - @Override public void debug(Marker marker, String msg) { throw new AssertionError(); } - @Override public void debug(Marker marker, String format, Object arg) { throw new AssertionError(); } - @Override public void debug(Marker marker, String format, Object arg1, Object arg2) { throw new AssertionError(); } - @Override public void debug(Marker marker, String format, Object... arguments) { throw new AssertionError(); } - @Override public void debug(Marker marker, String msg, Throwable t) { actual.debug(marker, msg, t); } - @Override public boolean isInfoEnabled() { return actual.isInfoEnabled(); } - @Override public void info(String msg) { throw new AssertionError(); } - @Override public void info(String format, Object arg) { throw new AssertionError(); } - @Override public void info(String format, Object arg1, Object arg2) { throw new AssertionError(); } - @Override public void info(String format, Object... arguments) { throw new AssertionError(); } - @Override public void info(String msg, Throwable t) { throw new AssertionError(); } - @Override public boolean isInfoEnabled(Marker marker) { return actual.isInfoEnabled(marker); } - @Override public void info(Marker marker, String msg) { throw new AssertionError(); } - @Override public void info(Marker marker, String format, Object arg) { throw new AssertionError(); } - @Override public void info(Marker marker, String format, Object arg1, Object arg2) { throw new AssertionError(); } - @Override public void info(Marker marker, String format, Object... arguments) { throw new AssertionError(); } - @Override public void info(Marker marker, String msg, Throwable t) { actual.info(marker, msg, t); } - @Override public boolean isWarnEnabled() { return actual.isWarnEnabled(); } - @Override public void warn(String msg) { throw new AssertionError(); } - @Override public void warn(String format, Object arg) { throw new AssertionError(); } - @Override public void warn(String format, Object... arguments) { throw new AssertionError(); } - @Override public void warn(String format, Object arg1, Object arg2) { throw new AssertionError(); } - @Override public void warn(String msg, Throwable t) { throw new AssertionError(); } - @Override public boolean isWarnEnabled(Marker marker) { return actual.isWarnEnabled(); } - @Override public void warn(Marker marker, String msg) { throw new AssertionError(); } - @Override public void warn(Marker marker, String format, Object arg) { throw new AssertionError(); } - @Override public void warn(Marker marker, String format, Object arg1, Object arg2) { throw new AssertionError(); } - @Override public void warn(Marker marker, String format, Object... arguments) { throw new AssertionError(); } - @Override public void warn(Marker marker, String msg, Throwable t) { actual.warn(marker, msg, t); } - @Override public boolean isErrorEnabled() { return actual.isErrorEnabled(); } - @Override public void error(String msg) { throw new AssertionError(); } - @Override public void error(String format, Object arg) { throw new AssertionError(); } - @Override public void error(String format, Object arg1, Object arg2) { throw new AssertionError(); } - @Override public void error(String format, Object... arguments) { throw new AssertionError(); } - @Override public void error(String msg, Throwable t) { throw new AssertionError(); } - @Override public boolean isErrorEnabled(Marker marker) { return actual.isErrorEnabled(marker); } - @Override public void error(Marker marker, String msg) { throw new AssertionError(); } - @Override public void error(Marker marker, String format, Object arg) { actual.error(marker, format, arg); } - @Override public void error(Marker marker, String format, Object arg1, Object arg2) { throw new AssertionError(); } - @Override public void error(Marker marker, String format, Object... arguments) { throw new AssertionError(); } - @Override public void error(Marker marker, String msg, Throwable t) { actual.error(marker, msg, t); } + + @Override + public String getName() { + return actual.getName(); + } + + @Override + public boolean isTraceEnabled() { + return actual.isTraceEnabled(); + } + + @Override + public void trace(String msg) { + throw new AssertionError(); + } + + @Override + public void trace(String format, Object arg) { + throw new AssertionError(); + } + + @Override + public void trace(String format, Object arg1, Object arg2) { + throw new AssertionError(); + } + + @Override + public void trace(String format, Object... arguments) { + throw new AssertionError(); + } + + @Override + public void trace(String msg, Throwable t) { + actual.trace(msg, t); + } + + @Override + public boolean isTraceEnabled(Marker marker) { + return actual.isTraceEnabled(); + } + + @Override + public void trace(Marker marker, String msg) { + throw new AssertionError(); + } + + @Override + public void trace(Marker marker, String format, Object arg) { + throw new AssertionError(); + } + + @Override + public void trace(Marker marker, String format, Object arg1, Object arg2) { + actual.trace(marker, format, arg1, arg2); + } + + @Override + public void trace(Marker marker, String format, Object... argArray) { + throw new AssertionError(); + } + + @Override + public void trace(Marker marker, String msg, Throwable t) { + actual.trace(marker, msg, t); + } + + @Override + public boolean isDebugEnabled() { + return actual.isDebugEnabled(); + } + + @Override + public void debug(String msg) { + throw new AssertionError(); + } + + @Override + public void debug(String format, Object arg) { + throw new AssertionError(); + } + + @Override + public void debug(String format, Object arg1, Object arg2) { + throw new AssertionError(); + } + + @Override + public void debug(String format, Object... arguments) { + throw new AssertionError(); + } + + @Override + public void debug(String msg, Throwable t) { + throw new AssertionError(); + } + + @Override + public boolean isDebugEnabled(Marker marker) { + return actual.isDebugEnabled(marker); + } + + @Override + public void debug(Marker marker, String msg) { + throw new AssertionError(); + } + + @Override + public void debug(Marker marker, String format, Object arg) { + throw new AssertionError(); + } + + @Override + public void debug(Marker marker, String format, Object arg1, Object arg2) { + throw new AssertionError(); + } + + @Override + public void debug(Marker marker, String format, Object... arguments) { + throw new AssertionError(); + } + + @Override + public void debug(Marker marker, String msg, Throwable t) { + actual.debug(marker, msg, t); + } + + @Override + public boolean isInfoEnabled() { + return actual.isInfoEnabled(); + } + + @Override + public void info(String msg) { + actual.info(msg); + } + + @Override + public void info(String format, Object arg) { + throw new AssertionError(); + } + + @Override + public void info(String format, Object arg1, Object arg2) { + throw new AssertionError(); + } + + @Override + public void info(String format, Object... arguments) { + throw new AssertionError(); + } + + @Override + public void info(String msg, Throwable t) { + actual.info(msg, t); + } + + @Override + public boolean isInfoEnabled(Marker marker) { + return actual.isInfoEnabled(marker); + } + + @Override + public void info(Marker marker, String msg) { + throw new AssertionError(); + } + + @Override + public void info(Marker marker, String format, Object arg) { + throw new AssertionError(); + } + + @Override + public void info(Marker marker, String format, Object arg1, Object arg2) { + throw new AssertionError(); + } + + @Override + public void info(Marker marker, String format, Object... arguments) { + throw new AssertionError(); + } + + @Override + public void info(Marker marker, String msg, Throwable t) { + actual.info(marker, msg, t); + } + + @Override + public boolean isWarnEnabled() { + return actual.isWarnEnabled(); + } + + @Override + public void warn(String msg) { + actual.warn(msg); + } + + @Override + public void warn(String format, Object arg) { + throw new AssertionError(); + } + + @Override + public void warn(String format, Object... arguments) { + throw new AssertionError(); + } + + @Override + public void warn(String format, Object arg1, Object arg2) { + throw new AssertionError(); + } + + @Override + public void warn(String msg, Throwable t) { + actual.warn(msg, t); + } + + @Override + public boolean isWarnEnabled(Marker marker) { + return actual.isWarnEnabled(); + } + + @Override + public void warn(Marker marker, String msg) { + throw new AssertionError(); + } + + @Override + public void warn(Marker marker, String format, Object arg) { + throw new AssertionError(); + } + + @Override + public void warn(Marker marker, String format, Object arg1, Object arg2) { + throw new AssertionError(); + } + + @Override + public void warn(Marker marker, String format, Object... arguments) { + throw new AssertionError(); + } + + @Override + public void warn(Marker marker, String msg, Throwable t) { + actual.warn(marker, msg, t); + } + + @Override + public boolean isErrorEnabled() { + return actual.isErrorEnabled(); + } + + @Override + public void error(String msg) { + actual.error(msg); + } + + @Override + public void error(String format, Object arg) { + throw new AssertionError(); + } + + @Override + public void error(String format, Object arg1, Object arg2) { + throw new AssertionError(); + } + + @Override + public void error(String format, Object... arguments) { + throw new AssertionError(); + } + + @Override + public void error(String msg, Throwable t) { + actual.error(msg, t); + } + + @Override + public boolean isErrorEnabled(Marker marker) { + return actual.isErrorEnabled(marker); + } + + @Override + public void error(Marker marker, String msg) { + throw new AssertionError(); + } + + @Override + public void error(Marker marker, String format, Object arg) { + actual.error(marker, format, arg); + } + + @Override + public void error(Marker marker, String format, Object arg1, Object arg2) { + throw new AssertionError(); + } + + @Override + public void error(Marker marker, String format, Object... arguments) { + throw new AssertionError(); + } + + @Override + public void error(Marker marker, String msg, Throwable t) { + actual.error(marker, msg, t); + } } } diff --git a/src/test/java/io/vertx/it/SLF4JNoImplTest.java b/src/test/java/io/vertx/it/SLF4JNoImplTest.java index c2a28ca8134..72f8ba918dc 100644 --- a/src/test/java/io/vertx/it/SLF4JNoImplTest.java +++ b/src/test/java/io/vertx/it/SLF4JNoImplTest.java @@ -11,28 +11,25 @@ package io.vertx.it; +import io.vertx.core.impl.logging.LoggerAdapter; +import io.vertx.core.impl.logging.LoggerFactory; import io.vertx.core.logging.JULLogDelegate; -import io.vertx.core.logging.Logger; -import io.vertx.core.logging.LoggerFactory; import io.vertx.core.logging.SLF4JLogDelegateFactory; import io.vertx.core.spi.logging.LogDelegate; import org.junit.Test; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; /** * Check the behavior when SLF4J is present on the classpath but without an implementation. * * @author Julien Viet */ -@SuppressWarnings("deprecation") public class SLF4JNoImplTest { - private static Object getClass(String name) { + private static Object getMessageClass() { try { - return Thread.currentThread().getContextClassLoader().loadClass(name); + return Thread.currentThread().getContextClassLoader().loadClass("org.apache.logging.log4j.message.Message"); } catch (Throwable e) { return null; } @@ -41,9 +38,9 @@ private static Object getClass(String name) { @Test public void testImplementation() { assertNotNull(SLF4JLogDelegateFactory.class); - assertNull(getClass("org.apache.logging.log4j.message.Message")); - Logger logger = LoggerFactory.getLogger("my-slf4j-logger"); - LogDelegate delegate = logger.getDelegate(); + assertNull(getMessageClass()); + LoggerAdapter loggerAdapter = (LoggerAdapter) LoggerFactory.getLogger("my-slf4j-logger"); + LogDelegate delegate = loggerAdapter.unwrap(); assertTrue(delegate instanceof JULLogDelegate); } } From b92d91c80ed7202e5bbd32cac952fc34e6041be6 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Wed, 14 Jun 2023 17:03:54 +0200 Subject: [PATCH 003/264] Updating a TCP server SSL options only affects the actual server (the first started) and other scaled servers will not see the SSL options update. Scaled TCP servers should use the actual server ssl channel handler provider in order to always use the most up to date SSL options. --- .../io/vertx/core/net/impl/TCPServerBase.java | 3 +- .../java/io/vertx/core/http/HttpTLSTest.java | 31 ++++++++++++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/vertx/core/net/impl/TCPServerBase.java b/src/main/java/io/vertx/core/net/impl/TCPServerBase.java index 4aa1bd081c0..d8434c29f72 100644 --- a/src/main/java/io/vertx/core/net/impl/TCPServerBase.java +++ b/src/main/java/io/vertx/core/net/impl/TCPServerBase.java @@ -268,9 +268,8 @@ private synchronized Future listen(SocketAddress localAddress, ContextI // Server already exists with that host/port - we will use that actualServer = main; metrics = main.metrics; - sslChannelProvider = main.sslChannelProvider; childHandler = childHandler(listenContext, localAddress, main.trafficShapingHandler); - worker = ch -> childHandler.accept(ch, sslChannelProvider.result().sslChannelProvider()); + worker = ch -> childHandler.accept(ch, actualServer.sslChannelProvider.result().sslChannelProvider()); actualServer.servers.add(this); actualServer.channelBalancer.addWorker(eventLoop, worker); listenContext.addCloseHook(this); diff --git a/src/test/java/io/vertx/core/http/HttpTLSTest.java b/src/test/java/io/vertx/core/http/HttpTLSTest.java index 1cf93a056c7..f259b11ba48 100755 --- a/src/test/java/io/vertx/core/http/HttpTLSTest.java +++ b/src/test/java/io/vertx/core/http/HttpTLSTest.java @@ -34,6 +34,7 @@ import javax.net.ssl.*; +import io.vertx.core.*; import io.vertx.core.impl.VertxThread; import io.vertx.core.net.SSLOptions; import io.vertx.core.net.impl.KeyStoreHelper; @@ -43,9 +44,6 @@ import org.junit.rules.TemporaryFolder; import io.netty.util.internal.PlatformDependent; -import io.vertx.core.Future; -import io.vertx.core.Vertx; -import io.vertx.core.VertxOptions; import io.vertx.core.buffer.Buffer; import io.vertx.core.net.JdkSSLEngineOptions; import io.vertx.core.net.JksOptions; @@ -1640,11 +1638,36 @@ public void testHAProxy() throws Exception { @Test public void testUpdateSSLOptions() throws Exception { + testUpdateSSLOptions(false); + } + + @Test + public void testUpdateSSLOptionsWithScaledServer() throws Exception { + testUpdateSSLOptions(true); + } + + private void testUpdateSSLOptions(boolean scaled) throws Exception { server = createHttpServer(createBaseServerOptions().setSsl(true).setKeyCertOptions(Cert.SERVER_JKS.get())) .requestHandler(req -> { req.response().end("Hello World"); - }); + }); startServer(testAddress); + if (scaled) { + awaitFuture(vertx.deployVerticle(new AbstractVerticle() { + private HttpServer server; + @Override + public void start(Promise startPromise) { + server = createHttpServer(createBaseServerOptions().setSsl(true).setKeyCertOptions(Cert.SERVER_JKS.get())) + .requestHandler(req -> { + req.response().end("Hello World"); + }); + server + .listen(testAddress) + .mapEmpty() + .onComplete(startPromise); + } + })); + } Supplier> request = () -> client.request(requestOptions).compose(req -> req.send().compose(HttpClientResponse::body)); client = createHttpClient(new HttpClientOptions().setKeepAlive(false).setSsl(true).setTrustOptions(Trust.SERVER_JKS.get())); request.get().onComplete(onSuccess(body1 -> { From afd587f6d6f79133b3a459079250dfb68680ce7c Mon Sep 17 00:00:00 2001 From: Thomas Segismont Date: Tue, 20 Jun 2023 14:45:08 +0200 Subject: [PATCH 004/264] Fix ConcurrentModificationException in BlockedThreadCheckerTest When using synchronized list, we shall synchronize while traversing. Signed-off-by: Thomas Segismont --- .../vertx/core/BlockedThreadCheckerTest.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/test/java/io/vertx/core/BlockedThreadCheckerTest.java b/src/test/java/io/vertx/core/BlockedThreadCheckerTest.java index 2879aaf097b..7c56e6907ed 100644 --- a/src/test/java/io/vertx/core/BlockedThreadCheckerTest.java +++ b/src/test/java/io/vertx/core/BlockedThreadCheckerTest.java @@ -15,7 +15,6 @@ import io.vertx.core.impl.btc.BlockedThreadEvent; import io.vertx.test.core.TestUtils; import io.vertx.test.core.VertxTestBase; -import org.junit.Assert; import org.junit.Test; import java.util.ArrayList; @@ -30,27 +29,28 @@ */ public class BlockedThreadCheckerTest extends VertxTestBase { - private volatile List events; + private final List events = Collections.synchronizedList(new ArrayList<>()); public void expectMessage(String poolName, long maxExecuteTime, TimeUnit maxExecuteTimeUnit) { - boolean match = events - .stream() - .anyMatch(event -> - event.thread().getName().startsWith(poolName) && - event.maxExecTime() == maxExecuteTimeUnit.toNanos(maxExecuteTime)); - Assert.assertTrue("Invalid events " + events, match); + List copy; + synchronized (events) { + copy = new ArrayList<>(events); + } + boolean match = false; + for (BlockedThreadEvent event : copy) { + if (event.thread().getName().startsWith(poolName) && + event.maxExecTime() == maxExecuteTimeUnit.toNanos(maxExecuteTime)) { + match = true; + break; + } + } + assertTrue("Invalid events: " + copy, match); } private void catchBlockedThreadEvents(Vertx vertx) { ((VertxInternal)vertx).blockedThreadChecker().setThreadBlockedHandler(event -> events.add(event)); } - @Override - public void setUp() throws Exception { - super.setUp(); - events = Collections.synchronizedList(new ArrayList<>()); - } - @Test public void testBlockCheckDefault() throws Exception { Verticle verticle = new AbstractVerticle() { From 5348750ece8ad0a800e3f0028dfff45bb0d21ff7 Mon Sep 17 00:00:00 2001 From: Thomas Segismont Date: Wed, 21 Jun 2023 08:54:25 +0200 Subject: [PATCH 005/264] Supported WAR files in FileResolver (#4747) See #4727 Signed-off-by: Thomas Segismont --- .../core/file/impl/FileResolverImpl.java | 26 ++++++---- .../vertx/core/file/WarFileResolverTest.java | 47 +++++++++++++++++++ 2 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 src/test/java/io/vertx/core/file/WarFileResolverTest.java diff --git a/src/main/java/io/vertx/core/file/impl/FileResolverImpl.java b/src/main/java/io/vertx/core/file/impl/FileResolverImpl.java index 65d6e0b919e..9d2e8a45dcf 100644 --- a/src/main/java/io/vertx/core/file/impl/FileResolverImpl.java +++ b/src/main/java/io/vertx/core/file/impl/FileResolverImpl.java @@ -279,24 +279,30 @@ private File unpackFromJarURL(URL url, String fileName, ClassLoader cl) { ZipFile zip = null; try { String path = url.getPath(); - int idx1 = path.lastIndexOf(".jar!"); - if (idx1 == -1) { - idx1 = path.lastIndexOf(".zip!"); - } - int idx2 = path.lastIndexOf(".jar!", idx1 - 1); - if (idx2 == -1) { - idx2 = path.lastIndexOf(".zip!", idx1 - 1); + int idx1 = -1, idx2 = -1; + for (int i = path.length() - 1; i > 4; ) { + if (path.charAt(i) == '!' && (path.startsWith(".jar", i - 4) || path.startsWith(".zip", i - 4) || path.startsWith(".war", i - 4))) { + if (idx1 == -1) { + idx1 = i; + i -= 4; + continue; + } else { + idx2 = i; + break; + } + } + i--; } if (idx2 == -1) { - File file = new File(decodeURIComponent(path.substring(5, idx1 + 4), false)); + File file = new File(decodeURIComponent(path.substring(5, idx1), false)); zip = new ZipFile(file); } else { - String s = path.substring(idx2 + 6, idx1 + 4); + String s = path.substring(idx2 + 2, idx1); File file = resolveFile(s); zip = new ZipFile(file); } - String inJarPath = path.substring(idx1 + 6); + String inJarPath = path.substring(idx1 + 2); StringBuilder prefixBuilder = new StringBuilder(); int first = 0; int second; diff --git a/src/test/java/io/vertx/core/file/WarFileResolverTest.java b/src/test/java/io/vertx/core/file/WarFileResolverTest.java new file mode 100644 index 00000000000..26e006845ef --- /dev/null +++ b/src/test/java/io/vertx/core/file/WarFileResolverTest.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011-2023 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.file; + +import io.vertx.test.core.TestUtils; +import org.junit.Assert; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; + +public class WarFileResolverTest extends FileResolverTestBase { + + static File getFiles(File baseDir) throws Exception { + File file = Files.createTempFile(TestUtils.MAVEN_TARGET_DIR.toPath(), "", "files.war").toFile(); + Assert.assertTrue(file.delete()); + return ZipFileResolverTest.getFiles( + baseDir, + file, + out -> { + try { + return new JarOutputStream(out); + } catch (IOException e) { + throw new AssertionError(e); + } + }, JarEntry::new); + } + + @Override + protected ClassLoader resourcesLoader(File baseDir) throws Exception { + File files = getFiles(baseDir); + return new URLClassLoader(new URL[]{files.toURI().toURL()}, Thread.currentThread().getContextClassLoader()); + } +} From 7bf7b3c721cd8db1f1f3cee518296231dd7ed280 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Thu, 22 Jun 2023 07:12:50 +0200 Subject: [PATCH 006/264] Update to brotli4j 1.12.0 for Netty 4.1.94.Final --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2cc0444a3cf..6fff141f831 100644 --- a/pom.xml +++ b/pom.xml @@ -195,7 +195,7 @@ com.aayushatharva.brotli4j brotli4j - 1.8.0 + 1.12.0 test From 4ec24fe69f3d53b7d7f7c6e6b94f867db7ddf5d1 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Thu, 22 Jun 2023 07:17:31 +0200 Subject: [PATCH 007/264] Remove null domain socket address workaround after upgrade to Netty 4.1.94.Final --- .../java/io/vertx/core/net/impl/ConnectionBase.java | 10 ++++++---- src/test/java/io/vertx/core/net/NetTest.java | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/vertx/core/net/impl/ConnectionBase.java b/src/main/java/io/vertx/core/net/impl/ConnectionBase.java index 1a5ad95e9dd..b1a324f40c0 100644 --- a/src/main/java/io/vertx/core/net/impl/ConnectionBase.java +++ b/src/main/java/io/vertx/core/net/impl/ConnectionBase.java @@ -628,6 +628,9 @@ public SocketAddress remoteAddress() { address = socketAdressOverride(REMOTE_ADDRESS_OVERRIDE); if (address == null) { address = channelRemoteAddress(); + if (address != null && address.isDomainSocket() && address.path().isEmpty()) { + address = channelLocalAddress(); + } } if (address != null) { remoteAddress = address; @@ -653,10 +656,6 @@ public SocketAddress remoteAddress(boolean real) { private SocketAddress channelLocalAddress() { java.net.SocketAddress addr = chctx.channel().localAddress(); - if (addr == null && channel().getClass().getSimpleName().endsWith("DomainSocketChannel")) { - // Workaround bug https://github.com/netty/netty/issues/13417 - return SocketAddress.domainSocketAddress(""); - } return addr != null ? vertx.transport().convert(addr) : null; } @@ -666,6 +665,9 @@ public SocketAddress localAddress() { address = socketAdressOverride(LOCAL_ADDRESS_OVERRIDE); if (address == null) { address = channelLocalAddress(); + if (address != null && address.isDomainSocket() && address.path().isEmpty()) { + address = channelRemoteAddress(); + } } if (address != null) { localAddress = address; diff --git a/src/test/java/io/vertx/core/net/NetTest.java b/src/test/java/io/vertx/core/net/NetTest.java index 74cc0a51db2..c0eccacd6ef 100755 --- a/src/test/java/io/vertx/core/net/NetTest.java +++ b/src/test/java/io/vertx/core/net/NetTest.java @@ -2141,7 +2141,7 @@ public void testSocketAddress() { assertEquals("127.0.0.1", addr.hostAddress()); } else { assertEquals(testAddress.path(), addr.path()); - assertEquals("", socket.remoteAddress().path()); + assertEquals(testAddress.path(), socket.remoteAddress().path()); } socket.close(); }).listen(testAddress).onComplete(onSuccess(v -> { @@ -2154,7 +2154,7 @@ public void testSocketAddress() { assertEquals(addr.port(), 1234); } else { assertEquals(testAddress.path(), addr.path()); - assertEquals("", socket.localAddress().path()); + assertEquals(testAddress.path(), socket.localAddress().path()); } socket.closeHandler(v2 -> testComplete()); })); From 99bc0da2f1230bd682289f31cef0a5c01868612f Mon Sep 17 00:00:00 2001 From: Francesco Nigro Date: Fri, 23 Jun 2023 09:23:24 +0200 Subject: [PATCH 008/264] Use fast thread local and fix GC nepotism (Fixes #4749) (#4750) * Use fast thread local and fix GC nepotism (Fixes #4749) * Replace order of reentrant task's merge --- .../core/net/impl/pool/CombinerExecutor.java | 62 ++++++++++--------- .../io/vertx/core/net/impl/pool/Task.java | 26 +++++++- 2 files changed, 55 insertions(+), 33 deletions(-) diff --git a/src/main/java/io/vertx/core/net/impl/pool/CombinerExecutor.java b/src/main/java/io/vertx/core/net/impl/pool/CombinerExecutor.java index b9083e2e108..eeb3a572dbc 100644 --- a/src/main/java/io/vertx/core/net/impl/pool/CombinerExecutor.java +++ b/src/main/java/io/vertx/core/net/impl/pool/CombinerExecutor.java @@ -10,6 +10,7 @@ */ package io.vertx.core.net.impl.pool; +import io.netty.util.concurrent.FastThreadLocal; import io.netty.util.internal.PlatformDependent; import java.util.Queue; @@ -27,7 +28,12 @@ public class CombinerExecutor implements Executor { private final Queue> q = PlatformDependent.newMpscQueue(); private final AtomicInteger s = new AtomicInteger(); private final S state; - private final ThreadLocal current = new ThreadLocal<>(); + + protected final class InProgressTail { + Task task; + } + + private final FastThreadLocal current = new FastThreadLocal<>(); public CombinerExecutor(S state) { this.state = state; @@ -40,50 +46,46 @@ public void submit(Action action) { return; } Task head = null; + Task tail = null; do { try { - head = pollAndExecute(head); + final Action a = q.poll(); + if (a == null) { + break; + } + Task task = a.execute(state); + if (task != null) { + if (head == null) { + assert tail == null; + tail = task; + head = task; + } else { + tail = tail.next(task); + } + } } finally { s.set(0); } } while (!q.isEmpty() && s.compareAndSet(0, 1)); if (head != null) { - Task inProgress = current.get(); + InProgressTail inProgress = current.get(); if (inProgress == null) { - current.set(head); + inProgress = new InProgressTail(); + current.set(inProgress); + inProgress.task = tail; try { - while (head != null) { - head.run(); - head = head.next; - } + // from now one cannot trust tail anymore + head.runNextTasks(); } finally { current.remove(); } } else { - merge(inProgress, head); - } - } - } + assert inProgress.task != null; + Task oldNextTail = inProgress.task.replaceNext(head); + assert oldNextTail == null; + inProgress.task = tail; - private Task pollAndExecute(Task head) { - Action action; - while ((action = q.poll()) != null) { - Task task = action.execute(state); - if (task != null) { - if (head == null) { - head = task; - } else { - merge(head, task); - } } } - return head; - } - - private static void merge(Task head, Task tail) { - Task tmp = tail.prev; - tail.prev = head.prev; - head.prev.next = tail; - head.prev = tmp; } } diff --git a/src/main/java/io/vertx/core/net/impl/pool/Task.java b/src/main/java/io/vertx/core/net/impl/pool/Task.java index b5a58064ffe..55f756d0053 100644 --- a/src/main/java/io/vertx/core/net/impl/pool/Task.java +++ b/src/main/java/io/vertx/core/net/impl/pool/Task.java @@ -12,9 +12,29 @@ public abstract class Task { - Task prev = this; - Task next; + private Task next; - public abstract void run(); + public Task replaceNext(Task next) { + Task oldNext = this.next; + this.next = next; + return oldNext; + } + + public Task next(Task next) { + this.next = next; + return next; + } + protected final void runNextTasks() { + Task task = this; + while (task != null) { + task.run(); + final Task next = task.next; + // help GC :P + task.next = null; + task = next; + } + } + + public abstract void run(); } From 6c80b1e9fcfab18b01c0de8a00009b515bd3fe4e Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Fri, 23 Jun 2023 17:18:23 +0200 Subject: [PATCH 009/264] Expose DnsClient TTL in MxRecord and SrvRecord responses. --- src/main/java/io/vertx/core/dns/MxRecord.java | 5 +++++ src/main/java/io/vertx/core/dns/SrvRecord.java | 5 +++++ src/main/java/io/vertx/core/dns/impl/MxRecordImpl.java | 8 +++++++- src/main/java/io/vertx/core/dns/impl/SrvRecordImpl.java | 9 ++++++++- .../io/vertx/core/dns/impl/decoder/RecordDecoder.java | 6 ++++-- src/test/java/io/vertx/core/dns/DNSTest.java | 2 ++ 6 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/vertx/core/dns/MxRecord.java b/src/main/java/io/vertx/core/dns/MxRecord.java index 75d705c6d66..e09f5d92d95 100644 --- a/src/main/java/io/vertx/core/dns/MxRecord.java +++ b/src/main/java/io/vertx/core/dns/MxRecord.java @@ -21,6 +21,11 @@ @VertxGen public interface MxRecord { + /** + * The record time to live + */ + long ttl(); + /** * The priority of the MX record. */ diff --git a/src/main/java/io/vertx/core/dns/SrvRecord.java b/src/main/java/io/vertx/core/dns/SrvRecord.java index 045a111c3f7..09140ed3538 100644 --- a/src/main/java/io/vertx/core/dns/SrvRecord.java +++ b/src/main/java/io/vertx/core/dns/SrvRecord.java @@ -27,6 +27,11 @@ public interface SrvRecord { */ int priority(); + /** + * Returns the record time to live + */ + long ttl(); + /** * Returns the weight of this service record. */ diff --git a/src/main/java/io/vertx/core/dns/impl/MxRecordImpl.java b/src/main/java/io/vertx/core/dns/impl/MxRecordImpl.java index b7e68bb0ea7..8fbc1c09482 100644 --- a/src/main/java/io/vertx/core/dns/impl/MxRecordImpl.java +++ b/src/main/java/io/vertx/core/dns/impl/MxRecordImpl.java @@ -18,14 +18,20 @@ */ public final class MxRecordImpl implements MxRecord, Comparable { + private final long ttl; private final int priority; private final String name; - public MxRecordImpl(int priority, String name) { + public MxRecordImpl(long ttl, int priority, String name) { + this.ttl = ttl; this.priority = priority; this.name = name; } + public long ttl() { + return ttl; + } + @Override public int priority() { return priority; diff --git a/src/main/java/io/vertx/core/dns/impl/SrvRecordImpl.java b/src/main/java/io/vertx/core/dns/impl/SrvRecordImpl.java index b98ddbfcc07..00759ab654d 100644 --- a/src/main/java/io/vertx/core/dns/impl/SrvRecordImpl.java +++ b/src/main/java/io/vertx/core/dns/impl/SrvRecordImpl.java @@ -18,6 +18,7 @@ */ public final class SrvRecordImpl implements SrvRecord, Comparable{ + private final long ttl; private final int priority; private final int weight; private final int port; @@ -26,7 +27,8 @@ public final class SrvRecordImpl implements SrvRecord, Comparable{ private final String service; private final String target; - public SrvRecordImpl(int priority, int weight, int port, String name, String protocol, String service, String target) { + public SrvRecordImpl(long ttl, int priority, int weight, int port, String name, String protocol, String service, String target) { + this.ttl = ttl; this.priority = priority; this.weight = weight; this.port = port; @@ -36,6 +38,11 @@ public SrvRecordImpl(int priority, int weight, int port, String name, String pro this.target = target; } + @Override + public long ttl() { + return ttl; + } + @Override public int priority() { return priority; diff --git a/src/main/java/io/vertx/core/dns/impl/decoder/RecordDecoder.java b/src/main/java/io/vertx/core/dns/impl/decoder/RecordDecoder.java index 2d8692ee4bd..741badbff8b 100644 --- a/src/main/java/io/vertx/core/dns/impl/decoder/RecordDecoder.java +++ b/src/main/java/io/vertx/core/dns/impl/decoder/RecordDecoder.java @@ -45,7 +45,8 @@ public class RecordDecoder { ByteBuf packet = ((DnsRawRecord)record).content(); int priority = packet.readShort(); String name = RecordDecoder.readName(packet); - return new MxRecordImpl(priority, name); + long ttl = record.timeToLive(); + return new MxRecordImpl(ttl, priority, name); }; /** @@ -83,12 +84,13 @@ public class RecordDecoder { int priority = packet.readShort(); int weight = packet.readShort(); int port = packet.readUnsignedShort(); + long ttl = record.timeToLive(); String target = RecordDecoder.readName(packet); String[] parts = record.name().split("\\.", 3); String service = parts[0]; String protocol = parts[1]; String name = parts[2]; - return new SrvRecordImpl(priority, weight, port, name, protocol, service, target); + return new SrvRecordImpl(ttl, priority, weight, port, name, protocol, service, target); }; /** diff --git a/src/test/java/io/vertx/core/dns/DNSTest.java b/src/test/java/io/vertx/core/dns/DNSTest.java index 8eb6d37689e..30ae7360e57 100644 --- a/src/test/java/io/vertx/core/dns/DNSTest.java +++ b/src/test/java/io/vertx/core/dns/DNSTest.java @@ -186,6 +186,7 @@ public void testResolveMX() throws Exception { assertFalse(result.isEmpty()); assertEquals(1, result.size()); MxRecord record = result.get(0); + assertEquals(100, record.ttl()); assertEquals(prio, record.priority()); assertEquals(record.name(), mxRecord); testComplete(); @@ -278,6 +279,7 @@ public void testResolveSRV() throws Exception { SrvRecord record = result.get(0); + assertEquals(100, record.ttl()); assertEquals(priority, record.priority()); assertEquals(weight, record.weight()); assertEquals(port, record.port()); From 1b7aa15d1bb3c7e1c10541aa36cf05e7275779e3 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Tue, 27 Jun 2023 08:53:05 +0200 Subject: [PATCH 010/264] Some resolver implementations obtain expirining results, the endpoint resolver can verify the validity of the results on behalf of the client. The AddressResolver interface now defines a method to check the validity of the resolver state, the endpoint now can call this method before obtaining a socket address and refresh the result when the state is stale. --- .../core/net/impl/pool/EndpointResolver.java | 29 +++++++++++++-- .../core/spi/resolver/AddressResolver.java | 10 ++++++ .../core/http/ResolvingHttpClientTest.java | 35 +++++++++++++++++++ 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/vertx/core/net/impl/pool/EndpointResolver.java b/src/main/java/io/vertx/core/net/impl/pool/EndpointResolver.java index eac1edc8051..10d0bc196bd 100644 --- a/src/main/java/io/vertx/core/net/impl/pool/EndpointResolver.java +++ b/src/main/java/io/vertx/core/net/impl/pool/EndpointResolver.java @@ -12,6 +12,7 @@ import io.vertx.core.Future; import io.vertx.core.impl.ContextInternal; +import io.vertx.core.impl.future.PromiseInternal; import io.vertx.core.net.Address; import io.vertx.core.net.SocketAddress; import io.vertx.core.spi.resolver.AddressResolver; @@ -75,7 +76,7 @@ public T withEndpoint(Address address, K key, Function, Optional public static class ResolvedEndpoint extends Endpoint { private final AtomicReference state; - private final Future resolved; + private final AtomicReference> resolved; private final AddressResolver resolver; private final ConnectionManager, C> connectionManager; private final ResolvingKey key; @@ -93,7 +94,7 @@ public ResolvedEndpoint(Future resolved, AddressResolver resolver, R state.set(ar.result()); } }); - this.resolved = fut; + this.resolved = new AtomicReference<>(fut); this.state = state; this.resolver = resolver; this.connectionManager = connectionManager; @@ -115,7 +116,29 @@ public void checkExpired() { @Override public Future requestConnection(ContextInternal ctx, long timeout) { - return resolved.compose(state -> resolver + Future fut = resolved.get(); + return fut.transform(ar -> { + if (ar.succeeded()) { + S state = ar.result(); + if (resolver.isValid(state)) { + return (Future) ar; + } else { + PromiseInternal promise = ctx.promise(); + if (resolved.compareAndSet(fut, promise.future())) { + resolver.resolve(key.address).andThen(ar2 -> { + if (ar2.succeeded()) { + ResolvedEndpoint.this.state.set(ar2.result()); + } + }).onComplete(promise); + return promise.future(); + } else { + return resolved.get(); + } + } + } else { + return (Future) ar; + } + }).compose(state -> resolver .pickAddress(state) .compose(origin -> { incRefCount(); diff --git a/src/main/java/io/vertx/core/spi/resolver/AddressResolver.java b/src/main/java/io/vertx/core/spi/resolver/AddressResolver.java index ff346c15113..14255fee941 100644 --- a/src/main/java/io/vertx/core/spi/resolver/AddressResolver.java +++ b/src/main/java/io/vertx/core/spi/resolver/AddressResolver.java @@ -44,6 +44,16 @@ public interface AddressResolver { */ Future resolve(A address); + /** + * Check the state validity. + * + * @param state the state to check + * @return whether the state is valid + */ + default boolean isValid(S state) { + return true; + } + /** * Pick a socket address for the state. * diff --git a/src/test/java/io/vertx/core/http/ResolvingHttpClientTest.java b/src/test/java/io/vertx/core/http/ResolvingHttpClientTest.java index 4b6ac752c54..860efb1b26c 100644 --- a/src/test/java/io/vertx/core/http/ResolvingHttpClientTest.java +++ b/src/test/java/io/vertx/core/http/ResolvingHttpClientTest.java @@ -46,13 +46,16 @@ static class FakeState { final List addresses; int index; final List metrics = Collections.synchronizedList(new ArrayList<>()); + volatile boolean valid; FakeState(String name, List addresses) { this.name = name; this.addresses = addresses; + this.valid = true; } FakeState(String name, SocketAddress... addresses) { this.name = name; this.addresses = new ArrayList<>(Arrays.asList(addresses)); + this.valid = true; } } @@ -106,6 +109,11 @@ private static class FixedAddressResolver implements AddressResolver map = new ConcurrentHashMap<>(); + @Override + public boolean isValid(FakeState state) { + return state.valid; + } + @Override public FakeMetric requestBegin(FakeState state, SocketAddress address) { FakeMetric metric = new FakeMetric(address); @@ -381,4 +389,31 @@ public void testStatistics() throws Exception { assertTrue(metric.responseBegin - metric.requestEnd > 500); assertTrue(metric.responseEnd - metric.responseBegin >= 0); } + + @Test + public void testInvalidation() throws Exception { + startServers(2); + requestHandler = (idx, req) -> { + req.response().end("" + idx); + }; + HttpClientInternal client = (HttpClientInternal) vertx.createHttpClient(); + FixedAddressResolver resolver = new FixedAddressResolver(); + SocketAddress addr1 = SocketAddress.inetSocketAddress(8080, "localhost"); + SocketAddress addr2 = SocketAddress.inetSocketAddress(8081, "localhost"); + resolver.map.put("example.com", new FakeState("example.com", addr1)); + client.addressResolver(resolver); + String res = awaitFuture(client.request(new FakeAddress("example.com"), HttpMethod.GET, 8080, "example.com", "/").compose(req -> req + .send() + .andThen(onSuccess(resp -> assertEquals(200, resp.statusCode()))) + .compose(HttpClientResponse::body) + )).toString(); + assertEquals("0", res); + resolver.map.put("example.com", new FakeState("example.com", addr2)).valid = false; + res = awaitFuture(client.request(new FakeAddress("example.com"), HttpMethod.GET, 8080, "example.com", "/").compose(req -> req + .send() + .andThen(onSuccess(resp -> assertEquals(200, resp.statusCode()))) + .compose(HttpClientResponse::body) + )).toString(); + assertEquals("1", res); + } } From c3aa9ac3ce897b5f6cc9775ddd16e28475746b3d Mon Sep 17 00:00:00 2001 From: franz1981 Date: Sun, 25 Jun 2023 11:49:04 +0200 Subject: [PATCH 011/264] Makes CombinerExecutor batchy again InProgressTail static --- .../core/net/impl/pool/CombinerExecutor.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/main/java/io/vertx/core/net/impl/pool/CombinerExecutor.java b/src/main/java/io/vertx/core/net/impl/pool/CombinerExecutor.java index eeb3a572dbc..4cbba5142e3 100644 --- a/src/main/java/io/vertx/core/net/impl/pool/CombinerExecutor.java +++ b/src/main/java/io/vertx/core/net/impl/pool/CombinerExecutor.java @@ -29,7 +29,7 @@ public class CombinerExecutor implements Executor { private final AtomicInteger s = new AtomicInteger(); private final S state; - protected final class InProgressTail { + protected static final class InProgressTail { Task task; } @@ -49,18 +49,20 @@ public void submit(Action action) { Task tail = null; do { try { - final Action a = q.poll(); - if (a == null) { - break; - } - Task task = a.execute(state); - if (task != null) { - if (head == null) { - assert tail == null; - tail = task; - head = task; - } else { - tail = tail.next(task); + for (; ; ) { + final Action a = q.poll(); + if (a == null) { + break; + } + Task task = a.execute(state); + if (task != null) { + if (head == null) { + assert tail == null; + tail = task; + head = task; + } else { + tail = tail.next(task); + } } } } finally { From 7bc52114b531d5afe68110e8eff08ccc97542a6b Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Thu, 29 Jun 2023 10:57:48 +0200 Subject: [PATCH 012/264] Update SLF4J to 2.0.7 --- pom.xml | 4 ++++ .../io/vertx/it/SLF4JLogDelegateTest.java | 21 +++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index 6fff141f831..b552c3e08b0 100644 --- a/pom.xml +++ b/pom.xml @@ -479,6 +479,10 @@ io/vertx/it/SLF4JLogDelegateTest.java + + System.out + false + diff --git a/src/test/java/io/vertx/it/SLF4JLogDelegateTest.java b/src/test/java/io/vertx/it/SLF4JLogDelegateTest.java index c88fd49bf9c..0f0a0d56a11 100644 --- a/src/test/java/io/vertx/it/SLF4JLogDelegateTest.java +++ b/src/test/java/io/vertx/it/SLF4JLogDelegateTest.java @@ -18,12 +18,10 @@ import io.vertx.core.spi.logging.LogDelegate; import org.junit.Test; import org.slf4j.Marker; -import org.slf4j.impl.SimpleLogger; import org.slf4j.spi.LocationAwareLogger; import java.io.ByteArrayOutputStream; import java.io.PrintStream; -import java.lang.reflect.Field; import java.util.concurrent.Callable; import static org.junit.Assert.*; @@ -112,22 +110,23 @@ private void testWarning(Logger logger) { assertTrue(result.contains("java.lang.NullPointerException")); } - private void setStream(PrintStream stream) { + private void withStream(PrintStream stream, Runnable runnable) { + PrintStream prev = System.out; + System.setOut(stream); try { - Field field = SimpleLogger.class.getDeclaredField("TARGET_STREAM"); - field.setAccessible(true); - field.set(null, stream); - } catch (Exception e) { - throw new IllegalStateException(e); + runnable.run(); + } finally { + System.setOut(prev); } } private String record(Runnable runnable) { ByteArrayOutputStream stream = new ByteArrayOutputStream(); PrintStream written = new PrintStream(stream); - setStream(written); - runnable.run(); - written.flush(); + withStream(written, () -> { + runnable.run(); + written.flush(); + }); String result = stream.toString(); quiet(() -> { written.close(); From 44dca58ac47d2f80e169bf80123c6e03e37137ef Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Tue, 4 Jul 2023 11:26:17 +0200 Subject: [PATCH 013/264] The DeliveryContextBase does not properly dispatch the event to its interceptors when the delivery happens from a non vertx thread, as it assumes that the delivery is synchronous. This updates the dispatch logic to the interceptor to always be synchronous and have the DeliveryContextBase state machine be correctly updated to make progress. --- .../eventbus/impl/DeliveryContextBase.java | 10 ++- .../eventbus/EventBusInterceptorTest.java | 68 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/vertx/core/eventbus/impl/DeliveryContextBase.java b/src/main/java/io/vertx/core/eventbus/impl/DeliveryContextBase.java index fcbe09d6617..9d4338b8d8a 100644 --- a/src/main/java/io/vertx/core/eventbus/impl/DeliveryContextBase.java +++ b/src/main/java/io/vertx/core/eventbus/impl/DeliveryContextBase.java @@ -61,7 +61,15 @@ public void next() { Handler interceptor = interceptors[interceptorIdx]; invoking = true; interceptorIdx++; - context.emit(this, interceptor); + if (context.inThread()) { + context.dispatch(this, interceptor); + } else { + try { + interceptor.handle(this); + } catch (Throwable t) { + context.reportException(t); + } + } invoking = false; if (!invokeNext) { return; diff --git a/src/test/java/io/vertx/core/eventbus/EventBusInterceptorTest.java b/src/test/java/io/vertx/core/eventbus/EventBusInterceptorTest.java index 7d29788d87d..5edb63b8c6e 100644 --- a/src/test/java/io/vertx/core/eventbus/EventBusInterceptorTest.java +++ b/src/test/java/io/vertx/core/eventbus/EventBusInterceptorTest.java @@ -355,6 +355,74 @@ private void testInboundInterceptorContext(boolean reply, boolean failure) { await(); } + @Test + public void testOutboundInterceptorFromNonVertxThreadDispatch() { + AtomicReference interceptorThread = new AtomicReference<>(); + eb.addOutboundInterceptor(sc -> { + interceptorThread.set(Thread.currentThread()); + }); + eb.consumer("some-address", msg -> { + }); + eb.send("some-address", "armadillo"); + assertSame(Thread.currentThread(), interceptorThread.get()); + } + + @Test + public void testOutboundInterceptorFromNonVertxThreadFailure() { + RuntimeException expected = new RuntimeException(); + eb.addOutboundInterceptor(sc -> { + throw expected; + }); + eb.consumer("some-address", msg -> { + }); + Context ctx = vertx.getOrCreateContext(); + AtomicReference caught = new AtomicReference<>(); + ctx.exceptionHandler(err -> caught.set(err)); + eb.send("some-address", "armadillo"); + assertSame(expected, caught.get()); + } + + @Test + public void testInboundInterceptorFromNonVertxThreadDispatch() { + AtomicReference interceptorThread = new AtomicReference<>(); + AtomicReference th = new AtomicReference<>(); + eb.addInboundInterceptor(sc -> { + new Thread(() -> { + th.set(Thread.currentThread()); + sc.next(); + }).start(); + }); + eb.addInboundInterceptor(sc -> { + interceptorThread.set(Thread.currentThread()); + }); + eb.consumer("some-address", msg -> { + }); + eb.send("some-address", "armadillo"); + waitUntil(() -> interceptorThread.get() != null); + assertSame(th.get(), interceptorThread.get()); + } + + @Test + public void testInboundInterceptorFromNonVertxThreadFailure() { + RuntimeException expected = new RuntimeException(); + eb.addInboundInterceptor(sc -> { + new Thread(() -> { + sc.next(); + }).start(); + }); + eb.addInboundInterceptor(sc -> { + throw expected; + }); + eb.consumer("some-address", msg -> { + }); + Context ctx = vertx.getOrCreateContext(); + AtomicReference caught = new AtomicReference<>(); + ctx.exceptionHandler(err -> caught.set(err)); + eb.send("some-address", "armadillo"); + waitUntil(() -> caught.get() != null); + assertSame(expected, caught.get()); + } + @Override public void setUp() throws Exception { super.setUp(); From 4492d5c7b344b256df732c50645ff52e878f2405 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Mon, 10 Jul 2023 16:26:34 +0200 Subject: [PATCH 014/264] The HttpClientRequest/HttpServerRequest expose the HTTP request authority using a host/port combination for the client request and a single host header for the server. In addition this terminology is also confusing with the server host and port. Deprecate and provide the request host/port accessors, replaced by an authority property modelled as an HostAndPort object. see #4777 --- src/main/asciidoc/http.adoc | 4 +- .../io/vertx/core/http/HttpClientRequest.java | 32 +--- .../io/vertx/core/http/HttpServerRequest.java | 5 +- .../vertx/core/http/HttpServerResponse.java | 24 ++- .../io/vertx/core/http/ServerWebSocket.java | 5 +- .../core/http/impl/Http1xServerRequest.java | 12 +- .../core/http/impl/Http1xServerResponse.java | 6 + .../core/http/impl/Http2ServerConnection.java | 17 +- .../core/http/impl/Http2ServerRequest.java | 6 +- .../core/http/impl/Http2ServerResponse.java | 30 +++- .../core/http/impl/Http2ServerStream.java | 8 +- .../core/http/impl/HttpClientRequestBase.java | 20 +-- .../http/impl/HttpServerRequestWrapper.java | 6 +- .../io/vertx/core/http/impl/HttpUtils.java | 13 +- .../core/http/impl/ServerWebSocketImpl.java | 10 +- .../java/io/vertx/core/net/HostAndPort.java | 33 ++++ .../vertx/core/net/impl/HostAndPortImpl.java | 162 ++++++++++++++++++ .../java/io/vertx/core/http/Http1xTest.java | 4 +- .../io/vertx/core/http/Http2ClientTest.java | 9 +- .../io/vertx/core/http/Http2ServerTest.java | 7 +- .../java/io/vertx/core/http/HttpTest.java | 13 +- .../io/vertx/core/http/HttpUtilsTest.java | 1 - .../io/vertx/core/http/WebSocketTest.java | 8 +- .../vertx/core/net/impl/HostAndPortTest.java | 70 ++++++++ 24 files changed, 406 insertions(+), 99 deletions(-) create mode 100644 src/main/java/io/vertx/core/net/HostAndPort.java create mode 100644 src/main/java/io/vertx/core/net/impl/HostAndPortImpl.java create mode 100644 src/test/java/io/vertx/core/net/impl/HostAndPortTest.java diff --git a/src/main/asciidoc/http.adoc b/src/main/asciidoc/http.adoc index 0091400f385..52d47065a45 100644 --- a/src/main/asciidoc/http.adoc +++ b/src/main/asciidoc/http.adoc @@ -182,9 +182,9 @@ It also has case-insensitive keys, that means you can do the following: {@link examples.HTTPExamples#example8} ---- -==== Request host +==== Request authority -Use {@link io.vertx.core.http.HttpServerRequest#host} to return the host of the HTTP request. +Use {@link io.vertx.core.http.HttpServerRequest#authority} to return the authority of the HTTP request. For HTTP/1.x requests the `host` header is returned, for HTTP/1 requests the `:authority` pseudo header is returned. diff --git a/src/main/java/io/vertx/core/http/HttpClientRequest.java b/src/main/java/io/vertx/core/http/HttpClientRequest.java index 78df6dc78c2..99ee80a331e 100644 --- a/src/main/java/io/vertx/core/http/HttpClientRequest.java +++ b/src/main/java/io/vertx/core/http/HttpClientRequest.java @@ -17,6 +17,7 @@ import io.vertx.core.Handler; import io.vertx.core.MultiMap; import io.vertx.core.buffer.Buffer; +import io.vertx.core.net.HostAndPort; import io.vertx.core.net.NetSocket; import io.vertx.core.streams.ReadStream; import io.vertx.core.streams.WriteStream; @@ -63,37 +64,14 @@ public interface HttpClientRequest extends WriteStream { HttpClientRequest drainHandler(Handler handler); /** - * Set the host value of the HTTP/1.1 {@code host} header or HTTP/2 {@code authority} pseudo header - *

The initial value is the same than the server socket address host. - *

Keep in mind that changing this value won't change the actual server socket address for this request. + * Set the request authority, when using HTTP/1.x this overrides the request {@code host} header, when using + * HTTP/2 this sets the {@code authority} pseudo header. * - * @param host the host part of the HTTP/1.1 {@code host} header or HTTP/2 {@code authority} pseudo header + * @param authority the authority * @return a reference to this, so the API can be used fluently */ @Fluent - HttpClientRequest setHost(String host); - - /** - * @return the host value of the HTTP/1.1 {@code host} header or HTTP/2 {@code authority} pseudo header - */ - String getHost(); - - /** - * Set the port value of the HTTP/1.1 {@code host} header or HTTP/2 {@code authority} pseudo header - * - *

Keep in mind that this won't change the actual server socket address for this request. - *

The initial value is the same than the server socket address port. - * - * @param port the port part of the HTTP/1.1 {@code host} header or HTTP/2 {@code authority} pseudo header - * @return a reference to this, so the API can be used fluently - */ - @Fluent - HttpClientRequest setPort(int port); - - /** - * @return the port value of the HTTP/1.1 {@code host} header or HTTP/2 {@code authority} pseudo header - */ - int getPort(); + HttpClientRequest authority(HostAndPort authority); /** * Set the request to follow HTTP redirects up to {@link HttpClientOptions#getMaxRedirects()}. diff --git a/src/main/java/io/vertx/core/http/HttpServerRequest.java b/src/main/java/io/vertx/core/http/HttpServerRequest.java index ba636869298..374dd0947e8 100644 --- a/src/main/java/io/vertx/core/http/HttpServerRequest.java +++ b/src/main/java/io/vertx/core/http/HttpServerRequest.java @@ -20,6 +20,7 @@ import io.vertx.core.Handler; import io.vertx.core.MultiMap; import io.vertx.core.buffer.Buffer; +import io.vertx.core.net.HostAndPort; import io.vertx.core.net.NetSocket; import io.vertx.core.net.SocketAddress; import io.vertx.core.streams.ReadStream; @@ -135,10 +136,10 @@ default boolean isSSL() { String query(); /** - * @return the request host. For HTTP2 it returns the {@literal :authority} pseudo header otherwise it returns the {@literal Host} header + * @return the request authority. For HTTP2 it returns the {@literal :authority} pseudo header otherwise it returns the {@literal Host} header */ @Nullable - String host(); + HostAndPort authority(); /** * @return the total number of bytes read for the body of the request. diff --git a/src/main/java/io/vertx/core/http/HttpServerResponse.java b/src/main/java/io/vertx/core/http/HttpServerResponse.java index 0d7ab37c0c0..3c49bea5b6c 100644 --- a/src/main/java/io/vertx/core/http/HttpServerResponse.java +++ b/src/main/java/io/vertx/core/http/HttpServerResponse.java @@ -17,6 +17,7 @@ import io.vertx.core.Handler; import io.vertx.core.MultiMap; import io.vertx.core.buffer.Buffer; +import io.vertx.core.net.HostAndPort; import io.vertx.core.streams.ReadStream; import io.vertx.core.streams.WriteStream; @@ -421,7 +422,7 @@ default Future push(HttpMethod method, String host, String p * Like {@link #push(HttpMethod, String, String, MultiMap)} with the host copied from the current request. */ default Future push(HttpMethod method, String path, MultiMap headers) { - return push(method, null, path, headers); + return push(method, (HostAndPort) null, path, headers); } /** @@ -431,6 +432,25 @@ default Future push(HttpMethod method, String path) { return push(method, null, path); } + /** + * Push a response to the client.

+ * + * The {@code handler} will be notified with a success when the push can be sent and with + * a failure when the client has disabled push or reset the push before it has been sent.

+ * + * The {@code handler} may be queued if the client has reduced the maximum number of streams the server can push + * concurrently.

+ * + * Push can be sent only for peer initiated streams and if the response is not ended. + * + * @param method the method of the promised request + * @param authority the authority of the promised request + * @param path the path of the promised request + * @param headers the headers of the promised request + * @return a future notified when the response can be written + */ + Future push(HttpMethod method, HostAndPort authority, String path, MultiMap headers); + /** * Push a response to the client.

* @@ -447,7 +467,9 @@ default Future push(HttpMethod method, String path) { * @param path the path of the promised request * @param headers the headers of the promised request * @return a future notified when the response can be written + * @deprecated instead use {@link #push(HttpMethod, HostAndPort, String, MultiMap)} */ + @Deprecated Future push(HttpMethod method, String host, String path, MultiMap headers); /** diff --git a/src/main/java/io/vertx/core/http/ServerWebSocket.java b/src/main/java/io/vertx/core/http/ServerWebSocket.java index 51a1126780d..17d86cdd856 100644 --- a/src/main/java/io/vertx/core/http/ServerWebSocket.java +++ b/src/main/java/io/vertx/core/http/ServerWebSocket.java @@ -18,6 +18,7 @@ import io.vertx.core.Handler; import io.vertx.core.Promise; import io.vertx.core.buffer.Buffer; +import io.vertx.core.net.HostAndPort; import javax.net.ssl.SSLSession; @@ -69,10 +70,10 @@ public interface ServerWebSocket extends WebSocketBase { String scheme(); /** - * @return the WebSocket handshake host + * @return the WebSocket handshake authority */ @Nullable - String host(); + HostAndPort authority(); /* * @return the WebSocket handshake URI. This is a relative URI. diff --git a/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java b/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java index 85698bd916b..3795cca39b9 100644 --- a/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java +++ b/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java @@ -17,7 +17,6 @@ import io.netty.handler.codec.http.multipart.Attribute; import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; import io.netty.handler.codec.http.multipart.InterfaceHttpData; -import io.vertx.codegen.annotations.Nullable; import io.vertx.core.Context; import io.vertx.core.Future; import io.vertx.core.Handler; @@ -32,6 +31,8 @@ import io.vertx.core.impl.future.PromiseInternal; import io.vertx.core.impl.logging.Logger; import io.vertx.core.impl.logging.LoggerFactory; +import io.vertx.core.net.HostAndPort; +import io.vertx.core.net.impl.HostAndPortImpl; import io.vertx.core.net.NetSocket; import io.vertx.core.net.SocketAddress; import io.vertx.core.spi.metrics.HttpServerMetrics; @@ -71,6 +72,7 @@ public class Http1xServerRequest extends HttpServerRequestInternal implements io private HttpRequest request; private io.vertx.core.http.HttpVersion version; private io.vertx.core.http.HttpMethod method; + private HostAndPort authority; private String uri; private String path; private String query; @@ -252,8 +254,12 @@ public String query() { } @Override - public @Nullable String host() { - return getHeader(HttpHeaderNames.HOST); + public synchronized HostAndPort authority() { + if (authority == null) { + String host = getHeader(HttpHeaderNames.HOST); + authority = HostAndPortImpl.parseHostAndPort(host, isSSL() ? 443 : 80); + } + return authority; } @Override diff --git a/src/main/java/io/vertx/core/http/impl/Http1xServerResponse.java b/src/main/java/io/vertx/core/http/impl/Http1xServerResponse.java index d682c498435..85a1da6ef0a 100644 --- a/src/main/java/io/vertx/core/http/impl/Http1xServerResponse.java +++ b/src/main/java/io/vertx/core/http/impl/Http1xServerResponse.java @@ -40,6 +40,7 @@ import io.vertx.core.impl.future.PromiseInternal; import io.vertx.core.impl.logging.Logger; import io.vertx.core.impl.logging.LoggerFactory; +import io.vertx.core.net.HostAndPort; import io.vertx.core.net.NetSocket; import io.vertx.core.spi.metrics.Metrics; import io.vertx.core.spi.observability.HttpResponse; @@ -733,6 +734,11 @@ public boolean reset(long code) { return true; } + @Override + public Future push(HttpMethod method, HostAndPort authority, String path, MultiMap headers) { + return context.failedFuture("HTTP/1 does not support response push"); + } + @Override public Future push(HttpMethod method, String host, String path, MultiMap headers) { return context.failedFuture("HTTP/1 does not support response push"); diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java b/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java index f0dfd84ef38..0c2e5270b7a 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java @@ -29,6 +29,7 @@ import io.vertx.core.http.*; import io.vertx.core.impl.ContextInternal; import io.vertx.core.impl.EventLoopContext; +import io.vertx.core.net.HostAndPort; import io.vertx.core.spi.metrics.HttpServerMetrics; import java.net.URI; @@ -176,22 +177,24 @@ protected synchronized void onHeadersRead(int streamId, Http2Headers headers, St } } - void sendPush(int streamId, String host, HttpMethod method, MultiMap headers, String path, StreamPriority streamPriority, Promise promise) { + void sendPush(int streamId, HostAndPort authority, HttpMethod method, MultiMap headers, String path, StreamPriority streamPriority, Promise promise) { EventLoop eventLoop = context.nettyEventLoop(); if (eventLoop.inEventLoop()) { - doSendPush(streamId, host, method, headers, path, streamPriority, promise); + doSendPush(streamId, authority, method, headers, path, streamPriority, promise); } else { - eventLoop.execute(() -> doSendPush(streamId, host, method, headers, path, streamPriority, promise)); + eventLoop.execute(() -> doSendPush(streamId, authority, method, headers, path, streamPriority, promise)); } } - private synchronized void doSendPush(int streamId, String host, HttpMethod method, MultiMap headers, String path, StreamPriority streamPriority, Promise promise) { + private synchronized void doSendPush(int streamId, HostAndPort authority, HttpMethod method, MultiMap headers, String path, StreamPriority streamPriority, Promise promise) { + boolean ssl = isSsl(); Http2Headers headers_ = new DefaultHttp2Headers(); headers_.method(method.name()); headers_.path(path); - headers_.scheme(isSsl() ? "https" : "http"); - if (host != null) { - headers_.authority(host); + headers_.scheme(ssl ? "https" : "http"); + if (authority != null) { + String s = (ssl && authority.port() == 443) || (!ssl && authority.port() == 80) ? authority.host() : authority.host() + ':' + authority.port(); + headers_.authority(s); } if (headers != null) { headers.forEach(header -> headers_.add(header.getKey(), header.getValue())); diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerRequest.java b/src/main/java/io/vertx/core/http/impl/Http2ServerRequest.java index 2e2546daae8..2f592427e78 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerRequest.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerRequest.java @@ -41,9 +41,9 @@ import io.vertx.core.impl.ContextInternal; import io.vertx.core.impl.logging.Logger; import io.vertx.core.impl.logging.LoggerFactory; +import io.vertx.core.net.HostAndPort; import io.vertx.core.net.NetSocket; import io.vertx.core.net.SocketAddress; -import io.vertx.core.tracing.TracingPolicy; import javax.net.ssl.SSLPeerUnverifiedException; import javax.security.cert.X509Certificate; @@ -334,8 +334,8 @@ public String scheme() { } @Override - public String host() { - return stream.host; + public @Nullable HostAndPort authority() { + return stream.authority; } @Override diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java b/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java index 3e5a4665606..b9e75664627 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java @@ -33,7 +33,9 @@ import io.vertx.core.http.StreamResetException; import io.vertx.core.http.impl.headers.Http2HeadersAdaptor; import io.vertx.core.impl.future.PromiseInternal; +import io.vertx.core.net.HostAndPort; import io.vertx.core.net.NetSocket; +import io.vertx.core.net.impl.HostAndPortImpl; import io.vertx.core.spi.observability.HttpResponse; import io.vertx.core.streams.ReadStream; @@ -614,18 +616,38 @@ public boolean reset(long code) { } @Override - public Future push(HttpMethod method, String host, String path, MultiMap headers) { + public Future push(HttpMethod method, HostAndPort authority, String path, MultiMap headers) { if (push) { throw new IllegalStateException("A push response cannot promise another push"); } - if (host == null) { - host = stream.host; + if (authority == null) { + authority = stream.authority; } synchronized (conn) { checkValid(); } Promise promise = stream.context.promise(); - conn.sendPush(stream.id(), host, method, headers, path, stream.priority(), promise); + conn.sendPush(stream.id(), authority, method, headers, path, stream.priority(), promise); + return promise.future(); + } + + @Override + public Future push(HttpMethod method, String authority, String path, MultiMap headers) { + if (push) { + throw new IllegalStateException("A push response cannot promise another push"); + } + HostAndPort hostAndPort = null; + if (authority != null) { + hostAndPort = HostAndPortImpl.parseHostAndPort(authority, conn.isSsl() ? 443 : 80); + } + if (hostAndPort == null) { + hostAndPort = stream.authority; + } + synchronized (conn) { + checkValid(); + } + Promise promise = stream.context.promise(); + conn.sendPush(stream.id(), hostAndPort, method, headers, path, stream.priority(), promise); return promise.future(); } diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java b/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java index e8ed6255366..119eb90a54f 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java @@ -22,6 +22,8 @@ import io.vertx.core.http.StreamPriority; import io.vertx.core.http.impl.headers.Http2HeadersAdaptor; import io.vertx.core.impl.ContextInternal; +import io.vertx.core.net.HostAndPort; +import io.vertx.core.net.impl.HostAndPortImpl; import io.vertx.core.spi.metrics.HttpServerMetrics; import io.vertx.core.spi.metrics.Metrics; import io.vertx.core.spi.observability.HttpRequest; @@ -36,7 +38,7 @@ class Http2ServerStream extends VertxHttp2Stream { protected final Http2Headers headers; protected final HttpMethod method; protected final String uri; - protected final String host; + protected final HostAndPort authority; private final TracingPolicy tracingPolicy; private Object metric; private Object trace; @@ -56,7 +58,7 @@ class Http2ServerStream extends VertxHttp2Stream { this.headers = null; this.method = method; this.uri = uri; - this.host = null; + this.authority = null; this.tracingPolicy = tracingPolicy; this.halfClosedRemote = halfClosedRemote; } @@ -71,7 +73,7 @@ class Http2ServerStream extends VertxHttp2Stream { } this.headers = headers; - this.host = host; + this.authority = HostAndPortImpl.parseHostAndPort(host, conn.isSsl() ? 443 : 80); this.uri = headers.get(":path") != null ? headers.get(":path").toString() : null; this.method = headers.get(":method") != null ? HttpMethod.valueOf(headers.get(":method").toString()) : null; this.tracingPolicy = tracingPolicy; diff --git a/src/main/java/io/vertx/core/http/impl/HttpClientRequestBase.java b/src/main/java/io/vertx/core/http/impl/HttpClientRequestBase.java index 5cd19681452..f19a44a8944 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpClientRequestBase.java +++ b/src/main/java/io/vertx/core/http/impl/HttpClientRequestBase.java @@ -12,7 +12,6 @@ package io.vertx.core.http.impl; import io.netty.handler.codec.http2.Http2Error; -import io.vertx.core.AsyncResult; import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.Promise; @@ -22,6 +21,7 @@ import io.vertx.core.http.StreamResetException; import io.vertx.core.impl.ContextInternal; import io.vertx.core.impl.future.PromiseInternal; +import io.vertx.core.net.HostAndPort; import io.vertx.core.net.SocketAddress; import java.util.Objects; @@ -123,20 +123,10 @@ public String getHost() { } @Override - public synchronized HttpClientRequest setHost(String host) { - Objects.requireNonNull(uri); - this.host = host; - return this; - } - - @Override - public int getPort() { - return port; - } - - @Override - public synchronized HttpClientRequest setPort(int port) { - this.port = port; + public synchronized HttpClientRequest authority(HostAndPort authority) { + Objects.requireNonNull(authority); + this.host = authority.host(); + this.port = authority.port(); return this; } diff --git a/src/main/java/io/vertx/core/http/impl/HttpServerRequestWrapper.java b/src/main/java/io/vertx/core/http/impl/HttpServerRequestWrapper.java index 21399853d08..d5e696d5bd6 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpServerRequestWrapper.java +++ b/src/main/java/io/vertx/core/http/impl/HttpServerRequestWrapper.java @@ -20,6 +20,7 @@ import io.vertx.core.http.HttpVersion; import io.vertx.core.http.ServerWebSocket; import io.vertx.core.http.StreamPriority; +import io.vertx.core.net.HostAndPort; import io.vertx.core.net.NetSocket; import io.vertx.core.net.SocketAddress; import io.vertx.core.streams.Pipe; @@ -119,9 +120,8 @@ public String query() { } @Override - @Nullable - public String host() { - return delegate.host(); + public @Nullable HostAndPort authority() { + return delegate.authority(); } @Override diff --git a/src/main/java/io/vertx/core/http/impl/HttpUtils.java b/src/main/java/io/vertx/core/http/impl/HttpUtils.java index b16e389e1a8..a8f7d3ef3ed 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpUtils.java +++ b/src/main/java/io/vertx/core/http/impl/HttpUtils.java @@ -31,6 +31,7 @@ import io.vertx.core.http.StreamPriority; import io.vertx.core.impl.ContextInternal; import io.vertx.core.impl.VertxInternal; +import io.vertx.core.net.HostAndPort; import io.vertx.core.spi.tracing.TagExtractor; import java.io.File; @@ -507,9 +508,15 @@ static String absoluteURI(String serverOrigin, HttpServerRequest req) throws URI if (scheme != null && (scheme.equals("http") || scheme.equals("https"))) { absoluteURI = uri.toString(); } else { - String host = req.host(); - if (host != null) { - absoluteURI = req.scheme() + "://" + host + uri; + boolean ssl = req.isSSL(); + HostAndPort authority = req.authority(); + if (authority != null) { + StringBuilder sb = new StringBuilder(req.scheme()).append("://").append(authority.host()); + if ((ssl && authority.port() != 443) || (!ssl && authority.port() != 80)) { + sb.append(':').append(authority.port()); + } + sb.append(uri); + absoluteURI = sb.toString(); } else { // Fall back to the server origin absoluteURI = serverOrigin + uri; diff --git a/src/main/java/io/vertx/core/http/impl/ServerWebSocketImpl.java b/src/main/java/io/vertx/core/http/impl/ServerWebSocketImpl.java index 74d8ccf9ffe..d5a6c1eccd9 100644 --- a/src/main/java/io/vertx/core/http/impl/ServerWebSocketImpl.java +++ b/src/main/java/io/vertx/core/http/impl/ServerWebSocketImpl.java @@ -16,10 +16,12 @@ import io.netty.channel.ChannelPipeline; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; +import io.vertx.codegen.annotations.Nullable; import io.vertx.core.*; import io.vertx.core.http.ServerWebSocket; import io.vertx.core.http.WebSocketFrame; import io.vertx.core.impl.ContextInternal; +import io.vertx.core.net.HostAndPort; import io.vertx.core.spi.metrics.HttpServerMetrics; import static io.netty.handler.codec.http.HttpResponseStatus.*; @@ -40,7 +42,7 @@ public class ServerWebSocketImpl extends WebSocketImplBase private final Http1xServerConnection conn; private final long closingTimeoutMS; private final String scheme; - private final String host; + private final HostAndPort authority; private final String uri; private final String path; private final String query; @@ -62,7 +64,7 @@ public class ServerWebSocketImpl extends WebSocketImplBase this.conn = conn; this.closingTimeoutMS = closingTimeout >= 0 ? closingTimeout * 1000L : -1L; this.scheme = request.scheme(); - this.host = request.host(); + this.authority = request.authority(); this.uri = request.uri(); this.path = request.path(); this.query = request.query(); @@ -76,8 +78,8 @@ public String scheme() { } @Override - public String host() { - return host; + public HostAndPort authority() { + return authority; } @Override diff --git a/src/main/java/io/vertx/core/net/HostAndPort.java b/src/main/java/io/vertx/core/net/HostAndPort.java new file mode 100644 index 00000000000..3ca7392b034 --- /dev/null +++ b/src/main/java/io/vertx/core/net/HostAndPort.java @@ -0,0 +1,33 @@ +package io.vertx.core.net; + +import io.vertx.codegen.annotations.VertxGen; +import io.vertx.core.net.impl.HostAndPortImpl; + +/** + * A combination of host and port. + */ +@VertxGen +public interface HostAndPort { + + /** + * Create an instance. + * + * @param host the host value + * @param port the port value + * @return the instance. + */ + static HostAndPort create(String host, int port) { + return new HostAndPortImpl(host, port); + } + + /** + * @return the host value + */ + String host(); + + /** + * @return the port value + */ + int port(); + +} diff --git a/src/main/java/io/vertx/core/net/impl/HostAndPortImpl.java b/src/main/java/io/vertx/core/net/impl/HostAndPortImpl.java new file mode 100644 index 00000000000..be153d14104 --- /dev/null +++ b/src/main/java/io/vertx/core/net/impl/HostAndPortImpl.java @@ -0,0 +1,162 @@ +package io.vertx.core.net.impl; + +import io.vertx.core.net.HostAndPort; + +public class HostAndPortImpl implements HostAndPort { + + static int parseHost(String val, int from, int to) { + int pos; + if ((pos = parseIPLiteral(val, from, to)) != -1) { + return pos; + } else if ((pos = parseIPv4Address(val, from, to)) != -1) { + return pos; + } else if ((pos = parseRegName(val, from, to)) != -1) { + return pos; + } + return -1; + } + + private static int foo(int v) { + return v == -1 ? -1 : v + 1; + } + + static int parseIPv4Address(String s, int from, int to) { + for (int i = 0;i < 4;i++) { + if (i > 0 && from < to && s.charAt(from++) != '.') { + return -1; + } + from = parseDecOctet(s, from, to); + if (from == -1) { + return -1; + } + } + return from; + } + + static int parseDecOctet(String s, int from, int to) { + int val = parseDigit(s, from++, to); + switch (val) { + case 0: + return from; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + int n = parseDigit(s, from, to); + if (n != -1) { + val = val * 10 + n; + n = parseDigit(s, ++from, to); + if (n != -1) { + from++; + val = val * 10 + n; + } + } + if (val < 256) { + return from; + } + } + return -1; + } + + private static int parseDigit(String s, int from, int to) { + char c; + return from < to && isDIGIT(c = s.charAt(from)) ? c - '0' : -1; + } + + public static int parseIPLiteral(String s, int from, int to) { + return from + 2 < to && s.charAt(from) == '[' ? foo(s.indexOf(']', from + 2)) : -1; + } + + public static int parseRegName(String s, int from, int to) { + while (from < to) { + char c = s.charAt(from); + if (isUnreserved(c) || isSubDelims(c)) { + from++; + } else if (c == '%' && (from + 2) < to && isHEXDIG(s.charAt(c + 1)) && isHEXDIG(s.charAt(c + 2))) { + from += 3; + } else { + break; + } + } + return from; + } + + private static boolean isUnreserved(char ch) { + return isALPHA(ch) || isDIGIT(ch) || ch == '-' || ch == '.' || ch == '_' || ch == '~'; + } + + private static boolean isALPHA(char ch) { + return ('A' <= ch && ch <= 'Z') + || ('a'<= ch && ch <= 'z'); + } + + private static boolean isDIGIT(char ch) { + return ('0' <= ch && ch <= '9'); + } + + private static boolean isSubDelims(char ch) { + return ch == '!' || ch == '$' || ch == '&' || ch == '\'' || ch == '(' || ch == ')' || ch == '*' || ch == '+' || ch == ',' || ch == ';' || ch == '='; + } + + static boolean isHEXDIG(char ch) { + return isDIGIT(ch) || ('A' <= ch && ch <= 'F') || ('a' <= ch && ch <= 'f'); + } + + /** + * Parse an authority HTTP header, that is host [':' port] + * @param s the string to port + * @param schemePort the scheme port used when the optional port is specified + * @return the parsed value or {@code null} when the string cannot be parsed + */ + public static HostAndPortImpl parseHostAndPort(String s, int schemePort) { + int pos = parseHost(s, 0, s.length()); + if (pos < 1) { + return null; + } + if (pos == s.length()) { + return new HostAndPortImpl(s, schemePort); + } + if (pos < s.length() && s.charAt(pos) == ':') { + String host = s.substring(0, pos); + int port = 0; + while (++pos < s.length()) { + int digit = parseDigit(s, pos, s.length()); + if (digit == -1) { + return null; + } + port = port * 10 + digit; + } + return new HostAndPortImpl(host, port); + } + return null; + } + + private final String host; + private final int port; + + public HostAndPortImpl(String host, int port) { + if (host == null) { + throw new NullPointerException(); + } + this.host = host; + this.port = port; + } + + public String host() { + return host; + } + + public int port() { + return port; + } + + @Override + public String toString() { + return host + ':' + port; + } +} diff --git a/src/test/java/io/vertx/core/http/Http1xTest.java b/src/test/java/io/vertx/core/http/Http1xTest.java index 346fafbb2eb..7be5d730473 100644 --- a/src/test/java/io/vertx/core/http/Http1xTest.java +++ b/src/test/java/io/vertx/core/http/Http1xTest.java @@ -3824,7 +3824,7 @@ public void testPerPeerPooling() throws Exception { .setServer(SocketAddress.inetSocketAddress(DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST)) .setPort(8080) .setHost("host" + i) - .setURI("/somepath")), HttpServerRequest::host); + .setURI("/somepath")), req -> req.authority().toString()); } @Test @@ -3840,7 +3840,7 @@ public void testPerPeerPoolingWithProxy() throws Exception { testPerXXXPooling((i) -> client.request(new RequestOptions() .setPort(80) .setHost("host" + i) - .setURI("/somepath")), HttpServerRequest::host); + .setURI("/somepath")), req -> req.authority().toString()); } private void testPerXXXPooling(Function> requestProvider, Function keyExtractor) throws Exception { diff --git a/src/test/java/io/vertx/core/http/Http2ClientTest.java b/src/test/java/io/vertx/core/http/Http2ClientTest.java index 0915bc7389f..757084cebba 100644 --- a/src/test/java/io/vertx/core/http/Http2ClientTest.java +++ b/src/test/java/io/vertx/core/http/Http2ClientTest.java @@ -276,7 +276,8 @@ public void testHeaders() throws Exception { assertEquals("https", req.scheme()); assertEquals(HttpMethod.GET, req.method()); assertEquals("/somepath", req.path()); - assertEquals(DEFAULT_HTTPS_HOST_AND_PORT, req.host()); + assertEquals(DEFAULT_HTTPS_HOST, req.authority().host()); + assertEquals(DEFAULT_HTTPS_PORT, req.authority().port()); assertEquals("foo_request_value", req.getHeader("Foo_request")); assertEquals("bar_request_value", req.getHeader("bar_request")); assertEquals(2, req.headers().getAll("juu_request").size()); @@ -362,7 +363,8 @@ private void testResponseBody(String expected) throws Exception { @Test public void testOverrideAuthority() throws Exception { server.requestHandler(req -> { - assertEquals("localhost:4444", req.host()); + assertEquals("localhost", req.authority().host()); + assertEquals(4444, req.authority().port()); req.response().end(); }); startServer(testAddress); @@ -1698,7 +1700,8 @@ public void testRejectClearTextUpgrade() throws Exception { } else { assertNull(upgrade); } - assertEquals(DEFAULT_HTTPS_HOST + ":" + DEFAULT_HTTPS_PORT, req.host()); + assertEquals(DEFAULT_HTTPS_HOST, req.authority().host()); + assertEquals(DEFAULT_HTTPS_PORT, req.authority().port()); req.response().end("wibble"); assertEquals(HttpVersion.HTTP_1_1, req.version()); }); diff --git a/src/test/java/io/vertx/core/http/Http2ServerTest.java b/src/test/java/io/vertx/core/http/Http2ServerTest.java index 69998c19ab5..18fb43801c5 100644 --- a/src/test/java/io/vertx/core/http/Http2ServerTest.java +++ b/src/test/java/io/vertx/core/http/Http2ServerTest.java @@ -429,7 +429,8 @@ public void testGet() throws Exception { }); HttpServerResponse resp = req.response(); assertEquals(HttpMethod.GET, req.method()); - assertEquals(DEFAULT_HTTPS_HOST_AND_PORT, req.host()); + assertEquals(DEFAULT_HTTPS_HOST, req.authority().host()); + assertEquals(DEFAULT_HTTPS_PORT, req.authority().port()); assertEquals("/", req.path()); assertTrue(req.isSSL()); assertEquals(expectedStreamId.get(), req.streamId()); @@ -519,7 +520,7 @@ public void testURI() throws Exception { assertEquals("foo=foo_value&bar=bar_value_1&bar=bar_value_2", req.query()); assertEquals("/some/path?foo=foo_value&bar=bar_value_1&bar=bar_value_2", req.uri()); assertEquals("http://whatever.com/some/path?foo=foo_value&bar=bar_value_1&bar=bar_value_2", req.absoluteURI()); - assertEquals("whatever.com", req.host()); + assertEquals("whatever.com", req.authority().host()); MultiMap params = req.params(); Set names = params.names(); assertEquals(2, names.size()); @@ -691,7 +692,7 @@ public void testPostFileUpload() throws Exception { public void testConnect() throws Exception { server.requestHandler(req -> { assertEquals(HttpMethod.CONNECT, req.method()); - assertEquals("whatever.com", req.host()); + assertEquals("whatever.com", req.authority().host()); assertNull(req.path()); assertNull(req.query()); assertNull(req.scheme()); diff --git a/src/test/java/io/vertx/core/http/HttpTest.java b/src/test/java/io/vertx/core/http/HttpTest.java index 0ba6430a265..4a98ecd79b4 100644 --- a/src/test/java/io/vertx/core/http/HttpTest.java +++ b/src/test/java/io/vertx/core/http/HttpTest.java @@ -35,11 +35,7 @@ import io.vertx.core.http.impl.headers.HeadersMultiMap; import io.vertx.core.impl.Utils; import io.vertx.core.impl.VertxInternal; -import io.vertx.core.net.NetClient; -import io.vertx.core.net.NetClientOptions; -import io.vertx.core.net.NetServerOptions; -import io.vertx.core.net.NetSocket; -import io.vertx.core.net.SocketAddress; +import io.vertx.core.net.*; import io.vertx.core.net.impl.HAProxyMessageCompletionHandler; import io.vertx.core.streams.Pump; import io.vertx.core.streams.ReadStream; @@ -347,7 +343,8 @@ public void testClientRequestOptionsSocketAddressOnly() throws Exception { String host = requestOptions.getHost(); server .requestHandler(request -> { - assertEquals(host + ":" + port, request.host()); + assertEquals(host, request.authority().host()); + assertEquals((int)port, request.authority().port()); request.response().end(); }); startServer(testAddress); @@ -3066,7 +3063,8 @@ private void testHttpClientResponsePausedDuringLastChunk(boolean fetching) throw @Test public void testHostHeaderOverridePossible() throws Exception { server.requestHandler(req -> { - assertEquals("localhost:4444", req.host()); + assertEquals("localhost", req.authority().host()); + assertEquals(4444, req.authority().port()); req.response().end(); }); @@ -4292,6 +4290,7 @@ class MockReq implements HttpClientRequest { public HttpClientRequest setMaxRedirects(int maxRedirects) { throw new UnsupportedOperationException(); } public HttpClientRequest setChunked(boolean chunked) { throw new UnsupportedOperationException(); } public boolean isChunked() { return false; } + public HttpClientRequest authority(HostAndPort authority) { throw new UnsupportedOperationException(); } public HttpMethod getMethod() { return method; } public String absoluteURI() { return baseURI; } public HttpVersion version() { return HttpVersion.HTTP_1_1; } diff --git a/src/test/java/io/vertx/core/http/HttpUtilsTest.java b/src/test/java/io/vertx/core/http/HttpUtilsTest.java index 2d51f7ea052..c189feaa858 100644 --- a/src/test/java/io/vertx/core/http/HttpUtilsTest.java +++ b/src/test/java/io/vertx/core/http/HttpUtilsTest.java @@ -229,5 +229,4 @@ private void check(String base, String ref, String expected) throws Exception { URI uri = HttpUtils.resolveURIReference(base, ref); assertEquals(expected, uri.getPath()); } - } diff --git a/src/test/java/io/vertx/core/http/WebSocketTest.java b/src/test/java/io/vertx/core/http/WebSocketTest.java index 919ba448ce9..666da6be432 100644 --- a/src/test/java/io/vertx/core/http/WebSocketTest.java +++ b/src/test/java/io/vertx/core/http/WebSocketTest.java @@ -623,14 +623,14 @@ private Future getUpgradedNetSocket(HttpServerRequest req, String pat private void testWSWriteStream(WebsocketVersion version) throws Exception { - String host = DEFAULT_HTTP_HOST + ":" + DEFAULT_HTTP_PORT; String scheme = "http"; String path = "/some/path"; String query = "handshake=bar&wibble=eek"; String uri = path + "?" + query; server = vertx.createHttpServer(new HttpServerOptions().setPort(DEFAULT_HTTP_PORT)).webSocketHandler(ws -> { - assertEquals(host, ws.host()); + assertEquals(DEFAULT_HTTP_HOST, ws.authority().host()); + assertEquals(DEFAULT_HTTP_PORT, ws.authority().port()); assertEquals(scheme, ws.scheme()); assertEquals(uri, ws.uri()); assertEquals(path, ws.path()); @@ -673,7 +673,6 @@ private void testWSWriteStream(WebsocketVersion version) throws Exception { } private void testWSFrames(boolean binary, WebsocketVersion version) throws Exception { - String host = DEFAULT_HTTP_HOST + ":" + DEFAULT_HTTP_PORT; String scheme = "http"; String path = "/some/path"; String query = "handshake=bar&wibble=eek"; @@ -683,7 +682,8 @@ private void testWSFrames(boolean binary, WebsocketVersion version) throws Excep int frames = version == WebsocketVersion.V00 ? 1: 10; server = vertx.createHttpServer(new HttpServerOptions().setPort(DEFAULT_HTTP_PORT)).webSocketHandler(ws -> { - assertEquals(host, ws.host()); + assertEquals(DEFAULT_HTTP_HOST, ws.authority().host()); + assertEquals(DEFAULT_HTTP_PORT, ws.authority().port()); assertEquals(scheme, ws.scheme()); assertEquals(uri, ws.uri()); assertEquals(path, ws.path()); diff --git a/src/test/java/io/vertx/core/net/impl/HostAndPortTest.java b/src/test/java/io/vertx/core/net/impl/HostAndPortTest.java new file mode 100644 index 00000000000..0f786b4acae --- /dev/null +++ b/src/test/java/io/vertx/core/net/impl/HostAndPortTest.java @@ -0,0 +1,70 @@ +package io.vertx.core.net.impl; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class HostAndPortTest { + + @Test + public void testParseIPLiteral() { + assertEquals(-1, HostAndPortImpl.parseIPLiteral("", 0, 0)); + assertEquals(-1, HostAndPortImpl.parseIPLiteral("[", 0, 1)); + assertEquals(-1, HostAndPortImpl.parseIPLiteral("[]", 0, 2)); + assertEquals(3, HostAndPortImpl.parseIPLiteral("[0]", 0, 3)); + assertEquals(-1, HostAndPortImpl.parseIPLiteral("[0", 0, 2)); + } + + @Test + public void testParseDecOctet() { + assertEquals(-1, HostAndPortImpl.parseDecOctet("", 0, 0)); + assertEquals(1, HostAndPortImpl.parseDecOctet("0", 0, 1)); + assertEquals(1, HostAndPortImpl.parseDecOctet("9", 0, 1)); + assertEquals(1, HostAndPortImpl.parseDecOctet("01", 0, 2)); + assertEquals(2, HostAndPortImpl.parseDecOctet("19", 0, 2)); + assertEquals(3, HostAndPortImpl.parseDecOctet("192", 0, 3)); + assertEquals(3, HostAndPortImpl.parseDecOctet("1234", 0, 4)); + assertEquals(-1, HostAndPortImpl.parseDecOctet("256", 0, 3)); + } + + @Test + public void testParseIPV4Address() { + assertEquals(-1, HostAndPortImpl.parseIPv4Address("0.0.0", 0, 5)); + assertEquals(-1, HostAndPortImpl.parseIPv4Address("0.0.0#0", 0, 7)); + assertEquals(7, HostAndPortImpl.parseIPv4Address("0.0.0.0", 0, 7)); + assertEquals(11, HostAndPortImpl.parseIPv4Address("192.168.0.0", 0, 11)); + assertEquals(-1, HostAndPortImpl.parseIPv4Address("011.168.0.0", 0, 11)); + } + + @Test + public void testParseRegName() { + assertEquals(5, HostAndPortImpl.parseRegName("abcdef", 0, 5)); + assertEquals(5, HostAndPortImpl.parseRegName("abcdef:1234", 0, 5)); + assertEquals(11, HostAndPortImpl.parseRegName("example.com", 0, 11)); + assertEquals(14, HostAndPortImpl.parseRegName("example-fr.com", 0, 14)); + } + + @Test + public void testParseHost() { + assertEquals(14, HostAndPortImpl.parseHost("example-fr.com", 0, 14)); + assertEquals(5, HostAndPortImpl.parseHost("[0::]", 0, 5)); + assertEquals(7, HostAndPortImpl.parseHost("0.0.0.0", 0, 7)); + } + + @Test + public void testParseHostAndPort() { + assertHostAndPort("example.com", 8080, "example.com:8080"); + assertHostAndPort("example.com", -1, "example.com"); + assertHostAndPort("0.1.2.3", -1, "0.1.2.3"); + assertHostAndPort("[0::]", -1, "[0::]"); + assertNull(HostAndPortImpl.parseHostAndPort("", -1)); + assertNull(HostAndPortImpl.parseHostAndPort("/", -1)); + } + + private void assertHostAndPort(String expectedHost, int expectedPort, String actual) { + HostAndPortImpl hostAndPort = HostAndPortImpl.parseHostAndPort(actual, -1); + assertNotNull(hostAndPort); + assertEquals(expectedHost, hostAndPort.host()); + assertEquals(expectedPort, hostAndPort.port()); + } +} From d999427590f0d93078e638e3c06c37f49b77d970 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Tue, 11 Jul 2023 15:14:35 +0200 Subject: [PATCH 015/264] An HTTP/2 server must consider a request with a host header different from request authority as malformed. Update the malformed request checker method to check the host header against the authority when present. see #4776 --- .../vertx/core/http/impl/Http2ServerConnection.java | 12 ++++++++++++ .../java/io/vertx/core/http/Http2ServerTest.java | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java b/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java index 0c2e5270b7a..32a364244f7 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java @@ -110,6 +110,18 @@ private static boolean isMalformedRequest(Http2Headers headers) { if (uri.getRawUserInfo() != null) { return true; } + CharSequence host = headers.get(HttpHeaders.HOST); + if (host != null) { + URI hostURI; + try { + hostURI = new URI(null, host.toString(), null, null, null); + } catch (URISyntaxException e) { + return true; + } + if (uri.getRawUserInfo() != null || !uri.getAuthority().equals(hostURI.getAuthority())) { + return true; + } + } } return false; } diff --git a/src/test/java/io/vertx/core/http/Http2ServerTest.java b/src/test/java/io/vertx/core/http/Http2ServerTest.java index 18fb43801c5..71238f3643b 100644 --- a/src/test/java/io/vertx/core/http/Http2ServerTest.java +++ b/src/test/java/io/vertx/core/http/Http2ServerTest.java @@ -1291,6 +1291,11 @@ public void testInvalidAuthority() throws Exception { testMalformedRequestHeaders(new DefaultHttp2Headers().method("GET").scheme("http").authority("foo@" + DEFAULT_HTTPS_HOST_AND_PORT).path("/")); } + @Test + public void testInvalidHost() throws Exception { + testMalformedRequestHeaders(new DefaultHttp2Headers().method("GET").scheme("http").authority(DEFAULT_HTTPS_HOST_AND_PORT).path("/").set("host", "something-else")); + } + @Test public void testConnectInvalidPath() throws Exception { testMalformedRequestHeaders(new DefaultHttp2Headers().method("CONNECT").path("/").authority(DEFAULT_HTTPS_HOST_AND_PORT)); From 403d122dff80f3a080d3dbde07f400391d987af9 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Wed, 12 Jul 2023 11:44:33 +0200 Subject: [PATCH 016/264] Make the HTTP authority more precise and allow to use a negative port to indicate the scheme default port should be used. - HttpServerRequest#authority() returns a negative port (-1) when the scheme default port is used - the implementation of HostAndPort#toString will not append the port when the port is negative --- .../java/io/vertx/core/http/HttpClientRequest.java | 10 ++++++---- .../java/io/vertx/core/http/HttpServerRequest.java | 3 ++- .../io/vertx/core/http/impl/Http1xServerRequest.java | 4 +++- .../io/vertx/core/http/impl/Http2ServerResponse.java | 2 +- .../io/vertx/core/http/impl/Http2ServerStream.java | 2 +- .../io/vertx/core/http/impl/HttpClientRequestBase.java | 6 +----- .../java/io/vertx/core/net/impl/HostAndPortImpl.java | 6 +++++- 7 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/main/java/io/vertx/core/http/HttpClientRequest.java b/src/main/java/io/vertx/core/http/HttpClientRequest.java index 99ee80a331e..71a7b47c771 100644 --- a/src/main/java/io/vertx/core/http/HttpClientRequest.java +++ b/src/main/java/io/vertx/core/http/HttpClientRequest.java @@ -12,7 +12,6 @@ package io.vertx.core.http; import io.vertx.codegen.annotations.*; -import io.vertx.core.AsyncResult; import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.MultiMap; @@ -64,10 +63,13 @@ public interface HttpClientRequest extends WriteStream { HttpClientRequest drainHandler(Handler handler); /** - * Set the request authority, when using HTTP/1.x this overrides the request {@code host} header, when using - * HTTP/2 this sets the {@code authority} pseudo header. + * Override the request authority, when using HTTP/1.x this overrides the request {@code host} header, when using + * HTTP/2 this sets the {@code authority} pseudo header. When the port is a negative value, the default + * scheme port will be used. * - * @param authority the authority + *

The default request authority is the server host and port when connecting to the server. + * + * @param authority override the request authority * @return a reference to this, so the API can be used fluently */ @Fluent diff --git a/src/main/java/io/vertx/core/http/HttpServerRequest.java b/src/main/java/io/vertx/core/http/HttpServerRequest.java index 374dd0947e8..d88a306e5ee 100644 --- a/src/main/java/io/vertx/core/http/HttpServerRequest.java +++ b/src/main/java/io/vertx/core/http/HttpServerRequest.java @@ -136,7 +136,8 @@ default boolean isSSL() { String query(); /** - * @return the request authority. For HTTP2 it returns the {@literal :authority} pseudo header otherwise it returns the {@literal Host} header + * @return the request authority. For HTTP2 it returns the {@literal :authority} pseudo header otherwise it returns the {@literal Host} header. + * When the authority string does not carry a port, the {@link HostAndPort#port()} returns {@code -1} to indicate the scheme port is prevalent. */ @Nullable HostAndPort authority(); diff --git a/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java b/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java index 3795cca39b9..21973cdb2fe 100644 --- a/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java +++ b/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java @@ -257,7 +257,9 @@ public String query() { public synchronized HostAndPort authority() { if (authority == null) { String host = getHeader(HttpHeaderNames.HOST); - authority = HostAndPortImpl.parseHostAndPort(host, isSSL() ? 443 : 80); + if (host != null) { + authority = HostAndPortImpl.parseHostAndPort(host, -1); + } } return authority; } diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java b/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java index b9e75664627..defc3a11bf8 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java @@ -638,7 +638,7 @@ public Future push(HttpMethod method, String authority, Stri } HostAndPort hostAndPort = null; if (authority != null) { - hostAndPort = HostAndPortImpl.parseHostAndPort(authority, conn.isSsl() ? 443 : 80); + hostAndPort = HostAndPortImpl.parseHostAndPort(authority, -1); } if (hostAndPort == null) { hostAndPort = stream.authority; diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java b/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java index 119eb90a54f..9d53444aa61 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java @@ -73,7 +73,7 @@ class Http2ServerStream extends VertxHttp2Stream { } this.headers = headers; - this.authority = HostAndPortImpl.parseHostAndPort(host, conn.isSsl() ? 443 : 80); + this.authority = HostAndPortImpl.parseHostAndPort(host, -1); this.uri = headers.get(":path") != null ? headers.get(":path").toString() : null; this.method = headers.get(":method") != null ? HttpMethod.valueOf(headers.get(":method").toString()) : null; this.tracingPolicy = tracingPolicy; diff --git a/src/main/java/io/vertx/core/http/impl/HttpClientRequestBase.java b/src/main/java/io/vertx/core/http/impl/HttpClientRequestBase.java index f19a44a8944..abda9f94093 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpClientRequestBase.java +++ b/src/main/java/io/vertx/core/http/impl/HttpClientRequestBase.java @@ -73,7 +73,7 @@ public abstract class HttpClientRequestBase implements HttpClientRequest { } protected String authority() { - if ((port == 80 && !ssl) || (port == 443 && ssl)) { + if ((port == 80 && !ssl) || (port == 443 && ssl) || port < 0) { return host; } else { return host + ':' + port; @@ -118,10 +118,6 @@ public synchronized HttpClientRequest setURI(String uri) { return this; } - public String getHost() { - return host; - } - @Override public synchronized HttpClientRequest authority(HostAndPort authority) { Objects.requireNonNull(authority); diff --git a/src/main/java/io/vertx/core/net/impl/HostAndPortImpl.java b/src/main/java/io/vertx/core/net/impl/HostAndPortImpl.java index be153d14104..147ac93191b 100644 --- a/src/main/java/io/vertx/core/net/impl/HostAndPortImpl.java +++ b/src/main/java/io/vertx/core/net/impl/HostAndPortImpl.java @@ -157,6 +157,10 @@ public int port() { @Override public String toString() { - return host + ':' + port; + if (port >= 0) { + return host + ':' + port; + } else { + return host; + } } } From 4b43eb64ffec6d47743d68fd5c0f689322545363 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Wed, 12 Jul 2023 12:30:43 +0200 Subject: [PATCH 017/264] Fix port computation regressions --- .../java/io/vertx/core/http/impl/Http2ServerConnection.java | 2 +- src/main/java/io/vertx/core/http/impl/HttpUtils.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java b/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java index 32a364244f7..549df1269c5 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerConnection.java @@ -205,7 +205,7 @@ private synchronized void doSendPush(int streamId, HostAndPort authority, HttpMe headers_.path(path); headers_.scheme(ssl ? "https" : "http"); if (authority != null) { - String s = (ssl && authority.port() == 443) || (!ssl && authority.port() == 80) ? authority.host() : authority.host() + ':' + authority.port(); + String s = (ssl && authority.port() == 443) || (!ssl && authority.port() == 80) || authority.port() <= 0 ? authority.host() : authority.host() + ':' + authority.port(); headers_.authority(s); } if (headers != null) { diff --git a/src/main/java/io/vertx/core/http/impl/HttpUtils.java b/src/main/java/io/vertx/core/http/impl/HttpUtils.java index a8f7d3ef3ed..b33351a153c 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpUtils.java +++ b/src/main/java/io/vertx/core/http/impl/HttpUtils.java @@ -512,7 +512,7 @@ static String absoluteURI(String serverOrigin, HttpServerRequest req) throws URI HostAndPort authority = req.authority(); if (authority != null) { StringBuilder sb = new StringBuilder(req.scheme()).append("://").append(authority.host()); - if ((ssl && authority.port() != 443) || (!ssl && authority.port() != 80)) { + if (authority.port() > 0 && (ssl && authority.port() != 443) || (!ssl && authority.port() != 80)) { sb.append(':').append(authority.port()); } sb.append(uri); From 54dafb638ef78e1e2948c21e4148f360149bd73f Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Wed, 12 Jul 2023 15:08:41 +0200 Subject: [PATCH 018/264] A few HTTP stream writeXXX API are fluent and instead should return a future signaling the success or failure of the write operation. Update the API (breaking change with fluent return) and the implementation to expose future results. --- .../io/vertx/core/http/HttpClientRequest.java | 6 ++--- .../vertx/core/http/HttpServerResponse.java | 9 +++----- .../http/impl/Http1xClientConnection.java | 2 +- .../http/impl/Http1xServerConnection.java | 6 +++-- .../core/http/impl/Http1xServerRequest.java | 2 +- .../core/http/impl/Http1xServerResponse.java | 12 +++++----- .../core/http/impl/Http2ServerResponse.java | 14 +++++++----- .../impl/Http2UpgradeClientConnection.java | 10 ++++----- .../core/http/impl/HttpClientRequestImpl.java | 5 ++--- .../impl/HttpClientRequestPushPromise.java | 2 +- .../core/http/impl/HttpClientStream.java | 2 +- .../StatisticsGatheringHttpClientStream.java | 4 ++-- .../impl/VertxHttp2ConnectionHandler.java | 5 +++-- .../core/http/impl/VertxHttp2Stream.java | 22 ++++++++++++++----- .../io/vertx/core/http/Http2ClientTest.java | 4 +++- .../io/vertx/core/http/Http2ServerTest.java | 4 +++- .../java/io/vertx/core/http/HttpTest.java | 2 +- 17 files changed, 64 insertions(+), 47 deletions(-) diff --git a/src/main/java/io/vertx/core/http/HttpClientRequest.java b/src/main/java/io/vertx/core/http/HttpClientRequest.java index 71a7b47c771..3ede203fd26 100644 --- a/src/main/java/io/vertx/core/http/HttpClientRequest.java +++ b/src/main/java/io/vertx/core/http/HttpClientRequest.java @@ -463,8 +463,7 @@ default boolean reset() { * @param payload the frame payload * @return a reference to this, so the API can be used fluently */ - @Fluent - HttpClientRequest writeCustomFrame(int type, int flags, Buffer payload); + Future writeCustomFrame(int type, int flags, Buffer payload); /** * @return the id of the stream of this response, {@literal -1} when it is not yet determined, i.e @@ -479,8 +478,7 @@ default int streamId() { * * @param frame the frame to write */ - @Fluent - default HttpClientRequest writeCustomFrame(HttpFrame frame) { + default Future writeCustomFrame(HttpFrame frame) { return writeCustomFrame(frame.type(), frame.flags(), frame.payload()); } diff --git a/src/main/java/io/vertx/core/http/HttpServerResponse.java b/src/main/java/io/vertx/core/http/HttpServerResponse.java index 3c49bea5b6c..c9532a2d7a8 100644 --- a/src/main/java/io/vertx/core/http/HttpServerResponse.java +++ b/src/main/java/io/vertx/core/http/HttpServerResponse.java @@ -229,8 +229,7 @@ public interface HttpServerResponse extends WriteStream { * Must only be used if the request contains an "Expect:100-Continue" header * @return a reference to this, so the API can be used fluently */ - @Fluent - HttpServerResponse writeContinue(); + Future writeContinue(); /** * Used to write an interim 103 Early Hints response to return some HTTP headers before the final HTTP message. @@ -504,16 +503,14 @@ default boolean reset() { * @param payload the frame payload * @return a reference to this, so the API can be used fluently */ - @Fluent - HttpServerResponse writeCustomFrame(int type, int flags, Buffer payload); + Future writeCustomFrame(int type, int flags, Buffer payload); /** * Like {@link #writeCustomFrame(int, int, Buffer)} but with an {@link HttpFrame}. * * @param frame the frame to write */ - @Fluent - default HttpServerResponse writeCustomFrame(HttpFrame frame) { + default Future writeCustomFrame(HttpFrame frame) { return writeCustomFrame(frame.type(), frame.flags(), frame.payload()); } diff --git a/src/main/java/io/vertx/core/http/impl/Http1xClientConnection.java b/src/main/java/io/vertx/core/http/impl/Http1xClientConnection.java index 7f1de2c9b67..952c16a6666 100644 --- a/src/main/java/io/vertx/core/http/impl/Http1xClientConnection.java +++ b/src/main/java/io/vertx/core/http/impl/Http1xClientConnection.java @@ -624,7 +624,7 @@ private void writeBuffer(ByteBuf buff, boolean end, FutureListener listene } @Override - public void writeFrame(int type, int flags, ByteBuf payload) { + public Future writeFrame(int type, int flags, ByteBuf payload) { throw new IllegalStateException("Cannot write an HTTP/2 frame over an HTTP/1.x connection"); } diff --git a/src/main/java/io/vertx/core/http/impl/Http1xServerConnection.java b/src/main/java/io/vertx/core/http/impl/Http1xServerConnection.java index 652ae15e528..4d373bb92a6 100644 --- a/src/main/java/io/vertx/core/http/impl/Http1xServerConnection.java +++ b/src/main/java/io/vertx/core/http/impl/Http1xServerConnection.java @@ -37,6 +37,7 @@ import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; import io.netty.handler.codec.http.websocketx.WebSocketVersion; import io.netty.util.ReferenceCountUtil; +import io.netty.util.concurrent.FutureListener; import io.vertx.core.AsyncResult; import io.vertx.core.Future; import io.vertx.core.Handler; @@ -455,8 +456,9 @@ public void handleInterestedOpsChanged() { context.execute(writable, handler); } - void write100Continue() { - chctx.writeAndFlush(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE)); + void write100Continue(FutureListener listener) { + ChannelPromise promise = listener == null ? chctx.voidPromise() : chctx.newPromise().addListener(listener); + chctx.writeAndFlush(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE), promise); } void write103EarlyHints(HttpHeaders headers, PromiseInternal promise) { diff --git a/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java b/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java index 21973cdb2fe..8327cdcd2e9 100644 --- a/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java +++ b/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java @@ -186,7 +186,7 @@ Http1xServerRequest next() { private void check100() { if (HttpUtil.is100ContinueExpected(request)) { - conn.write100Continue(); + conn.write100Continue(null); } } diff --git a/src/main/java/io/vertx/core/http/impl/Http1xServerResponse.java b/src/main/java/io/vertx/core/http/impl/Http1xServerResponse.java index 85a1da6ef0a..f5c6530e9c1 100644 --- a/src/main/java/io/vertx/core/http/impl/Http1xServerResponse.java +++ b/src/main/java/io/vertx/core/http/impl/Http1xServerResponse.java @@ -22,6 +22,7 @@ import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.LastHttpContent; +import io.netty.util.concurrent.FutureListener; import io.vertx.codegen.annotations.Nullable; import io.vertx.core.AsyncResult; import io.vertx.core.Future; @@ -341,9 +342,10 @@ public Future write(String chunk) { } @Override - public HttpServerResponse writeContinue() { - conn.write100Continue(); - return this; + public Future writeContinue() { + Promise promise = context.promise(); + conn.write100Continue((FutureListener) promise); + return promise.future(); } @Override @@ -745,8 +747,8 @@ public Future push(HttpMethod method, String host, String pa } @Override - public HttpServerResponse writeCustomFrame(int type, int flags, Buffer payload) { - return this; + public Future writeCustomFrame(int type, int flags, Buffer payload) { + return context.failedFuture("HTTP/1 does not support custom frames"); } CookieJar cookies() { diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java b/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java index defc3a11bf8..f4d62bca949 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java @@ -314,12 +314,13 @@ public HttpServerResponse endHandler(@Nullable Handler handler) { } @Override - public HttpServerResponse writeContinue() { + public Future writeContinue() { + Promise promise = stream.context.promise(); synchronized (conn) { checkHeadWritten(); - stream.writeHeaders(new DefaultHttp2Headers().status(HttpResponseStatus.CONTINUE.codeAsText()), false, null); - return this; + stream.writeHeaders(new DefaultHttp2Headers().status(HttpResponseStatus.CONTINUE.codeAsText()), false, promise); } + return promise.future(); } @Override @@ -482,14 +483,15 @@ private void setCookies() { } @Override - public HttpServerResponse writeCustomFrame(int type, int flags, Buffer payload) { + public Future writeCustomFrame(int type, int flags, Buffer payload) { + Promise promise = stream.context.promise(); synchronized (conn) { checkValid(); checkSendHeaders(false); - stream.writeFrame(type, flags, payload.getByteBuf()); + stream.writeFrame(type, flags, payload.getByteBuf(), promise); ctx.flush(); - return this; } + return promise.future(); } private void checkValid() { diff --git a/src/main/java/io/vertx/core/http/impl/Http2UpgradeClientConnection.java b/src/main/java/io/vertx/core/http/impl/Http2UpgradeClientConnection.java index 135d18a021a..af01879d5cd 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2UpgradeClientConnection.java +++ b/src/main/java/io/vertx/core/http/impl/Http2UpgradeClientConnection.java @@ -154,8 +154,8 @@ public Future writeBuffer(ByteBuf buf, boolean end) { } @Override - public void writeFrame(int type, int flags, ByteBuf payload) { - delegate.writeFrame(type, flags, payload); + public Future writeFrame(int type, int flags, ByteBuf payload) { + return delegate.writeFrame(type, flags, payload); } @Override @@ -699,11 +699,11 @@ public Future writeBuffer(ByteBuf buf, boolean end) { } @Override - public void writeFrame(int type, int flags, ByteBuf payload) { + public Future writeFrame(int type, int flags, ByteBuf payload) { if (upgradedStream != null) { - upgradedStream.writeFrame(type, flags, payload); + return upgradedStream.writeFrame(type, flags, payload); } else { - upgradingStream.writeFrame(type, flags, payload); + return upgradingStream.writeFrame(type, flags, payload); } } diff --git a/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl.java b/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl.java index 0e928fcd07f..4976642aac2 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl.java +++ b/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl.java @@ -263,12 +263,11 @@ public synchronized HttpConnection connection() { } @Override - public HttpClientRequest writeCustomFrame(int type, int flags, Buffer payload) { + public Future writeCustomFrame(int type, int flags, Buffer payload) { synchronized (this) { checkEnded(); } - stream.writeFrame(type, flags, payload.getByteBuf()); - return this; + return stream.writeFrame(type, flags, payload.getByteBuf()); } private void handleDrained(Void v) { diff --git a/src/main/java/io/vertx/core/http/impl/HttpClientRequestPushPromise.java b/src/main/java/io/vertx/core/http/impl/HttpClientRequestPushPromise.java index ac8f5e6b700..b5ab03fe2fb 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpClientRequestPushPromise.java +++ b/src/main/java/io/vertx/core/http/impl/HttpClientRequestPushPromise.java @@ -190,7 +190,7 @@ public StreamPriority getStreamPriority() { } @Override - public HttpClientRequest writeCustomFrame(int type, int flags, Buffer payload) { + public Future writeCustomFrame(int type, int flags, Buffer payload) { throw new UnsupportedOperationException("Cannot write frame with HTTP/1.x "); } } diff --git a/src/main/java/io/vertx/core/http/impl/HttpClientStream.java b/src/main/java/io/vertx/core/http/impl/HttpClientStream.java index ff91c482743..183db464594 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpClientStream.java +++ b/src/main/java/io/vertx/core/http/impl/HttpClientStream.java @@ -48,7 +48,7 @@ public interface HttpClientStream extends WriteStream { Future writeHead(HttpRequestHead request, boolean chunked, ByteBuf buf, boolean end, StreamPriority priority, boolean connect); Future writeBuffer(ByteBuf buf, boolean end); - void writeFrame(int type, int flags, ByteBuf payload); + Future writeFrame(int type, int flags, ByteBuf payload); void continueHandler(Handler handler); void earlyHintsHandler(Handler handler); diff --git a/src/main/java/io/vertx/core/http/impl/StatisticsGatheringHttpClientStream.java b/src/main/java/io/vertx/core/http/impl/StatisticsGatheringHttpClientStream.java index ea53da5e137..853b13846c3 100644 --- a/src/main/java/io/vertx/core/http/impl/StatisticsGatheringHttpClientStream.java +++ b/src/main/java/io/vertx/core/http/impl/StatisticsGatheringHttpClientStream.java @@ -93,8 +93,8 @@ public Future writeBuffer(ByteBuf buf, boolean end) { } @Override - public void writeFrame(int type, int flags, ByteBuf payload) { - delegate.writeFrame(type, flags, payload); + public Future writeFrame(int type, int flags, ByteBuf payload) { + return delegate.writeFrame(type, flags, payload); } @Override diff --git a/src/main/java/io/vertx/core/http/impl/VertxHttp2ConnectionHandler.java b/src/main/java/io/vertx/core/http/impl/VertxHttp2ConnectionHandler.java index ee1ff0b0011..a551a2740eb 100644 --- a/src/main/java/io/vertx/core/http/impl/VertxHttp2ConnectionHandler.java +++ b/src/main/java/io/vertx/core/http/impl/VertxHttp2ConnectionHandler.java @@ -278,8 +278,9 @@ void consume(Http2Stream stream, int numBytes) { } } - void writeFrame(Http2Stream stream, byte type, short flags, ByteBuf payload) { - encoder().writeFrame(chctx, type, stream.id(), new Http2Flags(flags), payload, chctx.newPromise()); + void writeFrame(Http2Stream stream, byte type, short flags, ByteBuf payload, FutureListener listener) { + ChannelPromise promise = listener == null ? chctx.voidPromise() : chctx.newPromise().addListener(listener); + encoder().writeFrame(chctx, type, stream.id(), new Http2Flags(flags), payload, promise); checkFlush(); } diff --git a/src/main/java/io/vertx/core/http/impl/VertxHttp2Stream.java b/src/main/java/io/vertx/core/http/impl/VertxHttp2Stream.java index 318b2f5c719..0e79bf5ad57 100644 --- a/src/main/java/io/vertx/core/http/impl/VertxHttp2Stream.java +++ b/src/main/java/io/vertx/core/http/impl/VertxHttp2Stream.java @@ -18,6 +18,7 @@ import io.netty.handler.codec.http2.Http2Headers; import io.netty.handler.codec.http2.Http2Stream; import io.netty.util.concurrent.FutureListener; +import io.vertx.core.Future; import io.vertx.core.MultiMap; import io.vertx.core.Promise; import io.vertx.core.buffer.Buffer; @@ -163,17 +164,28 @@ public synchronized boolean isNotWritable() { return !writable; } - public final void writeFrame(int type, int flags, ByteBuf payload) { + public final Future writeFrame(int type, int flags, ByteBuf payload) { + Promise promise = context.promise(); EventLoop eventLoop = conn.getContext().nettyEventLoop(); if (eventLoop.inEventLoop()) { - doWriteFrame(type, flags, payload); + doWriteFrame(type, flags, payload, promise); } else { - eventLoop.execute(() -> doWriteFrame(type, flags, payload)); + eventLoop.execute(() -> doWriteFrame(type, flags, payload, promise)); } + return promise.future(); } - private void doWriteFrame(int type, int flags, ByteBuf payload) { - conn.handler.writeFrame(stream, (byte) type, (short) flags, payload); + public final void writeFrame(int type, int flags, ByteBuf payload, Promise promise) { + EventLoop eventLoop = conn.getContext().nettyEventLoop(); + if (eventLoop.inEventLoop()) { + doWriteFrame(type, flags, payload, promise); + } else { + eventLoop.execute(() -> doWriteFrame(type, flags, payload, promise)); + } + } + + private void doWriteFrame(int type, int flags, ByteBuf payload, Promise promise) { + conn.handler.writeFrame(stream, (byte) type, (short) flags, payload, (FutureListener) promise); } final void writeHeaders(Http2Headers headers, boolean end, Promise promise) { diff --git a/src/test/java/io/vertx/core/http/Http2ClientTest.java b/src/test/java/io/vertx/core/http/Http2ClientTest.java index 757084cebba..4139ebcc7f5 100644 --- a/src/test/java/io/vertx/core/http/Http2ClientTest.java +++ b/src/test/java/io/vertx/core/http/Http2ClientTest.java @@ -1597,7 +1597,9 @@ public void testUnknownFrame() throws Exception { assertEquals(10, frame.type()); assertEquals(253, frame.flags()); assertEquals(expectedSend, frame.payload()); - req.response().writeCustomFrame(12, 134, expectedRecv).end(); + HttpServerResponse resp = req.response(); + resp.writeCustomFrame(12, 134, expectedRecv); + resp.end(); }); }); startServer(testAddress); diff --git a/src/test/java/io/vertx/core/http/Http2ServerTest.java b/src/test/java/io/vertx/core/http/Http2ServerTest.java index 71238f3643b..71ec88e5c02 100644 --- a/src/test/java/io/vertx/core/http/Http2ServerTest.java +++ b/src/test/java/io/vertx/core/http/Http2ServerTest.java @@ -2529,7 +2529,9 @@ public void testUnknownFrame() throws Exception { assertEquals(10, frame.type()); assertEquals(253, frame.flags()); assertEquals(expectedSend, frame.payload()); - req.response().writeCustomFrame(12, 134, expectedRecv).end(); + HttpServerResponse resp = req.response(); + resp.writeCustomFrame(12, 134, expectedRecv); + resp.end(); }); }); startServer(ctx); diff --git a/src/test/java/io/vertx/core/http/HttpTest.java b/src/test/java/io/vertx/core/http/HttpTest.java index 4a98ecd79b4..9a89b58f6b3 100644 --- a/src/test/java/io/vertx/core/http/HttpTest.java +++ b/src/test/java/io/vertx/core/http/HttpTest.java @@ -4328,7 +4328,7 @@ class MockReq implements HttpClientRequest { public boolean reset(long code) { return false; } public boolean reset(long code, Throwable cause) { return false; } public HttpConnection connection() { throw new UnsupportedOperationException(); } - public HttpClientRequest writeCustomFrame(int type, int flags, Buffer payload) { throw new UnsupportedOperationException(); } + public Future writeCustomFrame(int type, int flags, Buffer payload) { throw new UnsupportedOperationException(); } public boolean writeQueueFull() { throw new UnsupportedOperationException(); } public StreamPriority getStreamPriority() { return null; } public HttpClientRequest onComplete(Handler> handler) { throw new UnsupportedOperationException(); } From 8396d05d02b118325a7656f86e696570402d4f38 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Tue, 11 Jul 2023 10:01:43 +0200 Subject: [PATCH 019/264] When the HTTP/2 server sends a complete response (HttpServerResponse#end) when there is no read in progress, the server will flush two times instead of one. The server has been modified to aggregate flushes in such situation. --- .../core/http/impl/Http2ClientConnection.java | 8 ++++---- .../vertx/core/http/impl/Http2ServerResponse.java | 14 +++++++++----- .../io/vertx/core/http/impl/Http2ServerStream.java | 4 ++-- .../http/impl/VertxHttp2ConnectionHandler.java | 6 ++++-- .../io/vertx/core/http/impl/VertxHttp2Stream.java | 10 +++++----- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/main/java/io/vertx/core/http/impl/Http2ClientConnection.java b/src/main/java/io/vertx/core/http/impl/Http2ClientConnection.java index 3b0beca28f7..aa50bca5276 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ClientConnection.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ClientConnection.java @@ -263,9 +263,9 @@ void doWriteData(ByteBuf chunk, boolean end, Promise promise) { } @Override - void doWriteHeaders(Http2Headers headers, boolean end, Promise promise) { + void doWriteHeaders(Http2Headers headers, boolean end, boolean checkFlush, Promise promise) { isConnect = "CONNECT".contentEquals(headers.method()); - super.doWriteHeaders(headers, end, promise); + super.doWriteHeaders(headers, end, checkFlush, promise); } @Override @@ -575,10 +575,10 @@ private void writeHeaders(HttpRequestHead request, ByteBuf buf, boolean end, Str return; } if (buf != null) { - doWriteHeaders(headers, false, null); + doWriteHeaders(headers, false, false, null); doWriteData(buf, e, promise); } else { - doWriteHeaders(headers, e, promise); + doWriteHeaders(headers, e, true, promise); } } diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java b/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java index f4d62bca949..d49b69a83dd 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java @@ -318,7 +318,7 @@ public Future writeContinue() { Promise promise = stream.context.promise(); synchronized (conn) { checkHeadWritten(); - stream.writeHeaders(new DefaultHttp2Headers().status(HttpResponseStatus.CONTINUE.codeAsText()), false, promise); + stream.writeHeaders(new DefaultHttp2Headers().status(HttpResponseStatus.CONTINUE.codeAsText()), false, true, promise); } return promise.future(); } @@ -334,7 +334,7 @@ public Future writeEarlyHints(MultiMap headers) { synchronized (conn) { checkHeadWritten(); } - stream.writeHeaders(http2Headers, false, promise); +; stream.writeHeaders(http2Headers, false, true, promise); return promise.future(); } @@ -408,7 +408,7 @@ Future write(ByteBuf chunk, boolean end) { if (end && !headWritten && needsContentLengthHeader()) { headers().set(HttpHeaderNames.CONTENT_LENGTH, String.valueOf(chunk.readableBytes())); } - boolean sent = checkSendHeaders(end && !hasBody && trailers == null); + boolean sent = checkSendHeaders(end && !hasBody && trailers == null, !hasBody); if (hasBody || (!sent && end)) { Promise p = stream.context.promise(); fut = p.future(); @@ -417,7 +417,7 @@ Future write(ByteBuf chunk, boolean end) { fut = stream.context.succeededFuture(); } if (end && trailers != null) { - stream.writeHeaders(trailers, true, null); + stream.writeHeaders(trailers, true, true, null); } bodyEndHandler = this.bodyEndHandler; endHandler = this.endHandler; @@ -438,6 +438,10 @@ private boolean needsContentLengthHeader() { } private boolean checkSendHeaders(boolean end) { + return checkSendHeaders(end, true); + } + + private boolean checkSendHeaders(boolean end, boolean checkFlush) { if (!headWritten) { if (headersEndHandler != null) { headersEndHandler.handle(null); @@ -447,7 +451,7 @@ private boolean checkSendHeaders(boolean end) { } prepareHeaders(); headWritten = true; - stream.writeHeaders(headers, end, null); + stream.writeHeaders(headers, end, checkFlush, null); if (end) { ctx.flush(); } diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java b/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java index 9d53444aa61..407f98ec504 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerStream.java @@ -125,14 +125,14 @@ void onEnd(MultiMap trailers) { } @Override - void doWriteHeaders(Http2Headers headers, boolean end, Promise promise) { + void doWriteHeaders(Http2Headers headers, boolean end, boolean checkFlush, Promise promise) { if (Metrics.METRICS_ENABLED && !end) { HttpServerMetrics metrics = conn.metrics(); if (metrics != null) { metrics.responseBegin(metric, request.response()); } } - super.doWriteHeaders(headers, end, promise); + super.doWriteHeaders(headers, end, checkFlush, promise); } @Override diff --git a/src/main/java/io/vertx/core/http/impl/VertxHttp2ConnectionHandler.java b/src/main/java/io/vertx/core/http/impl/VertxHttp2ConnectionHandler.java index a551a2740eb..ffb76a449f8 100644 --- a/src/main/java/io/vertx/core/http/impl/VertxHttp2ConnectionHandler.java +++ b/src/main/java/io/vertx/core/http/impl/VertxHttp2ConnectionHandler.java @@ -220,10 +220,12 @@ public void onGoAwayReceived(int lastStreamId, long errorCode, ByteBuf debugData // - void writeHeaders(Http2Stream stream, Http2Headers headers, boolean end, int streamDependency, short weight, boolean exclusive, FutureListener listener) { + void writeHeaders(Http2Stream stream, Http2Headers headers, boolean end, int streamDependency, short weight, boolean exclusive, boolean checkFlush, FutureListener listener) { ChannelPromise promise = listener == null ? chctx.voidPromise() : chctx.newPromise().addListener(listener); encoder().writeHeaders(chctx, stream.id(), headers, streamDependency, weight, exclusive, 0, end, promise); - checkFlush(); + if (checkFlush) { + checkFlush(); + } } void writeData(Http2Stream stream, ByteBuf chunk, boolean end, FutureListener listener) { diff --git a/src/main/java/io/vertx/core/http/impl/VertxHttp2Stream.java b/src/main/java/io/vertx/core/http/impl/VertxHttp2Stream.java index 0e79bf5ad57..930021931b6 100644 --- a/src/main/java/io/vertx/core/http/impl/VertxHttp2Stream.java +++ b/src/main/java/io/vertx/core/http/impl/VertxHttp2Stream.java @@ -188,17 +188,17 @@ private void doWriteFrame(int type, int flags, ByteBuf payload, Promise pr conn.handler.writeFrame(stream, (byte) type, (short) flags, payload, (FutureListener) promise); } - final void writeHeaders(Http2Headers headers, boolean end, Promise promise) { + final void writeHeaders(Http2Headers headers, boolean end, boolean checkFlush, Promise promise) { EventLoop eventLoop = conn.getContext().nettyEventLoop(); if (eventLoop.inEventLoop()) { - doWriteHeaders(headers, end, promise); + doWriteHeaders(headers, end, checkFlush, promise); } else { - eventLoop.execute(() -> doWriteHeaders(headers, end, promise)); + eventLoop.execute(() -> doWriteHeaders(headers, end, checkFlush, promise)); } } - void doWriteHeaders(Http2Headers headers, boolean end, Promise promise) { - conn.handler.writeHeaders(stream, headers, end, priority.getDependency(), priority.getWeight(), priority.isExclusive(), (FutureListener) promise); + void doWriteHeaders(Http2Headers headers, boolean end, boolean checkFlush, Promise promise) { + conn.handler.writeHeaders(stream, headers, end, priority.getDependency(), priority.getWeight(), priority.isExclusive(), checkFlush, (FutureListener) promise); if (end) { endWritten(); } From 535d6daa9135a76360ef302d7fdae0d185bf6792 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Tue, 11 Jul 2023 10:34:11 +0200 Subject: [PATCH 020/264] Remove a few un-necessaries flushes in Http2ServerResponse --- .../java/io/vertx/core/http/impl/Http2ServerResponse.java | 5 ----- .../java/io/vertx/core/spi/tracing/HttpTracerTestBase.java | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java b/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java index d49b69a83dd..1d7f2f9e500 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java @@ -381,7 +381,6 @@ Future netSocket() { if (!checkSendHeaders(false)) { netSocket = stream.context.failedFuture("Response for CONNECT already sent"); } else { - ctx.flush(); HttpNetSocket ns = HttpNetSocket.netSocket(conn, stream.context, (ReadStream) stream.request, this); netSocket = Future.succeededFuture(ns); } @@ -452,9 +451,6 @@ private boolean checkSendHeaders(boolean end, boolean checkFlush) { prepareHeaders(); headWritten = true; stream.writeHeaders(headers, end, checkFlush, null); - if (end) { - ctx.flush(); - } return true; } else { return false; @@ -493,7 +489,6 @@ public Future writeCustomFrame(int type, int flags, Buffer payload) { checkValid(); checkSendHeaders(false); stream.writeFrame(type, flags, payload.getByteBuf(), promise); - ctx.flush(); } return promise.future(); } diff --git a/src/test/java/io/vertx/core/spi/tracing/HttpTracerTestBase.java b/src/test/java/io/vertx/core/spi/tracing/HttpTracerTestBase.java index aad2af1ff72..0a63386aea2 100644 --- a/src/test/java/io/vertx/core/spi/tracing/HttpTracerTestBase.java +++ b/src/test/java/io/vertx/core/spi/tracing/HttpTracerTestBase.java @@ -66,7 +66,7 @@ public void sendResponse(Context context, Object response, Object payload, Throw assertEquals(1, seq.get()); ContextInternal ctx = (ContextInternal) Vertx.currentContext(); assertSame(val, ctx.localContextData().get(key)); - req.response().endHandler(v -> { + req.response().closeHandler(v -> { assertNull(ctx.localContextData().get(key)); assertEquals(2, seq.get()); }); From 2045ed3615cdd755f10b66f48a5828ae8b539daa Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Thu, 13 Jul 2023 10:09:28 +0200 Subject: [PATCH 021/264] Implement execute blocking with callable --- src/main/asciidoc/index.adoc | 6 +- src/main/java/examples/CoreExamples.java | 10 +-- src/main/java/io/vertx/core/Context.java | 49 ++++++++++-- src/main/java/io/vertx/core/Vertx.java | 50 +++++++++++- .../java/io/vertx/core/WorkerExecutor.java | 38 ++++++++- .../java/io/vertx/core/impl/ContextBase.java | 80 ++++++++++++++++--- .../io/vertx/core/impl/ContextInternal.java | 7 ++ .../io/vertx/core/impl/DuplicatedContext.java | 21 +++++ .../core/impl/NoStackTraceException.java | 28 +++++++ .../io/vertx/core/impl/VertxInternal.java | 11 +++ .../java/io/vertx/core/impl/VertxWrapper.java | 21 +++++ .../vertx/core/impl/WorkerExecutorImpl.java | 8 ++ src/test/java/io/vertx/core/FakeContext.java | 21 +++++ 13 files changed, 318 insertions(+), 32 deletions(-) create mode 100644 src/main/java/io/vertx/core/impl/NoStackTraceException.java diff --git a/src/main/asciidoc/index.adoc b/src/main/asciidoc/index.adoc index e7df5bdc9d6..82d4241870e 100644 --- a/src/main/asciidoc/index.adoc +++ b/src/main/asciidoc/index.adoc @@ -603,8 +603,8 @@ blocking APIs safely within a Vert.x application. As discussed before, you can't call blocking operations directly from an event loop, as that would prevent it from doing any other useful work. So how can you do this? -It's done by calling {@link io.vertx.core.Vertx#executeBlocking} specifying both the blocking code to execute and a -result handler to be called back asynchronous when the blocking code has been executed. +It's done by calling {@link io.vertx.core.Vertx#executeBlocking} with blocking code to execute, as return you get a +future completed with the result of the blocking code execution. [source,$lang] ---- @@ -621,7 +621,7 @@ which can interact with verticles using the event-bus or {@link io.vertx.core.Co By default, if executeBlocking is called several times from the same context (e.g. the same verticle instance) then the different executeBlocking are executed _serially_ (i.e. one after another). -If you don't care about ordering you can call {@link io.vertx.core.Vertx#executeBlocking(io.vertx.core.Handler,boolean)} +If you don't care about ordering you can call {@link io.vertx.core.Vertx#executeBlocking(java.util.concurrent.Callable,boolean)} specifying `false` as the argument to `ordered`. In this case any executeBlocking may be executed in parallel on the worker pool. diff --git a/src/main/java/examples/CoreExamples.java b/src/main/java/examples/CoreExamples.java index ed697b5e31f..361c99fe66e 100644 --- a/src/main/java/examples/CoreExamples.java +++ b/src/main/java/examples/CoreExamples.java @@ -67,10 +67,9 @@ public void example6(HttpServer server) { } public void example7(Vertx vertx) { - vertx.executeBlocking(promise -> { + vertx.executeBlocking(() -> { // Call some blocking API that takes a significant amount of time to return - String result = someAPI.blockingMethod("hello"); - promise.complete(result); + return someAPI.blockingMethod("hello"); }).onComplete(res -> { System.out.println("The result is: " + res.result()); }); @@ -78,10 +77,9 @@ public void example7(Vertx vertx) { public void workerExecutor1(Vertx vertx) { WorkerExecutor executor = vertx.createSharedWorkerExecutor("my-worker-pool"); - executor.executeBlocking(promise -> { + executor.executeBlocking(() -> { // Call some blocking API that takes a significant amount of time to return - String result = someAPI.blockingMethod("hello"); - promise.complete(result); + return someAPI.blockingMethod("hello"); }).onComplete(res -> { System.out.println("The result is: " + res.result()); }); diff --git a/src/main/java/io/vertx/core/Context.java b/src/main/java/io/vertx/core/Context.java index 31dda087740..80651ad5d66 100644 --- a/src/main/java/io/vertx/core/Context.java +++ b/src/main/java/io/vertx/core/Context.java @@ -20,6 +20,7 @@ import io.vertx.core.json.JsonObject; import java.util.List; +import java.util.concurrent.Callable; /** * The execution context of a {@link io.vertx.core.Handler} execution. @@ -105,8 +106,8 @@ static boolean isOnVertxThread() { *

* Executes the blocking code in the handler {@code blockingCodeHandler} using a thread from the worker pool. *

- * When the code is complete the handler {@code resultHandler} will be called with the result on the original context - * (e.g. on the original event loop of the caller). + * The returned future will be completed with the result on the original context (i.e. on the original event loop of the caller) + * or failed when the handler throws an exception. *

* A {@code Future} instance is passed into {@code blockingCodeHandler}. When the blocking code successfully completes, * the handler should call the {@link Promise#complete} or {@link Promise#complete(Object)} method, or the {@link Promise#fail} @@ -130,13 +131,51 @@ static boolean isOnVertxThread() { */ Future<@Nullable T> executeBlocking(Handler> blockingCodeHandler, boolean ordered); + /** + * Safely execute some blocking code. + *

+ * Executes the blocking code in the handler {@code blockingCodeHandler} using a thread from the worker pool. + *

+ * The returned future will be completed with the result on the original context (i.e. on the original event loop of the caller) + * or failed when the handler throws an exception. + *

+ * The blocking code should block for a reasonable amount of time (i.e no more than a few seconds). Long blocking operations + * or polling operations (i.e a thread that spin in a loop polling events in a blocking fashion) are precluded. + *

+ * When the blocking operation lasts more than the 10 seconds, a message will be printed on the console by the + * blocked thread checker. + *

+ * Long blocking operations should use a dedicated thread managed by the application, which can interact with + * verticles using the event-bus or {@link Context#runOnContext(Handler)} + * + * @param blockingCodeHandler handler representing the blocking code to run + * @param ordered if true then if executeBlocking is called several times on the same context, the executions + * for that context will be executed serially, not in parallel. if false then they will be no ordering + * guarantees + * @param the type of the result + * @return a future completed when the blocking code is complete + */ + @GenIgnore(GenIgnore.PERMITTED_TYPE) + Future<@Nullable T> executeBlocking(Callable blockingCodeHandler, boolean ordered); + /** * Invoke {@link #executeBlocking(Handler, boolean)} with order = true. * @param blockingCodeHandler handler representing the blocking code to run * @param the type of the result * @return a future completed when the blocking code is complete */ - default Future executeBlocking(Handler> blockingCodeHandler) { + default Future<@Nullable T> executeBlocking(Handler> blockingCodeHandler) { + return executeBlocking(blockingCodeHandler, true); + } + + /** + * Invoke {@link #executeBlocking(Callable, boolean)} with order = true. + * @param blockingCodeHandler handler representing the blocking code to run + * @param the type of the result + * @return a future completed when the blocking code is complete + */ + @GenIgnore(GenIgnore.PERMITTED_TYPE) + default Future<@Nullable T> executeBlocking(Callable blockingCodeHandler) { return executeBlocking(blockingCodeHandler, true); } @@ -165,7 +204,7 @@ default List processArgs() { /** * Is the current context an event loop context? *

- * NOTE! when running blocking code using {@link io.vertx.core.Vertx#executeBlocking(Handler, Handler)} from a + * NOTE! when running blocking code using {@link io.vertx.core.Vertx#executeBlocking(Callable)} from a * standard (not worker) verticle, the context will still an event loop context and this {@link this#isEventLoopContext()} * will return true. * @@ -176,7 +215,7 @@ default List processArgs() { /** * Is the current context a worker context? *

- * NOTE! when running blocking code using {@link io.vertx.core.Vertx#executeBlocking(Handler, Handler)} from a + * NOTE! when running blocking code using {@link io.vertx.core.Vertx#executeBlocking(Callable)} from a * standard (not worker) verticle, the context will still an event loop context and this {@link this#isWorkerContext()} * will return false. * diff --git a/src/main/java/io/vertx/core/Vertx.java b/src/main/java/io/vertx/core/Vertx.java index 2ddb3826186..4ad9684837b 100644 --- a/src/main/java/io/vertx/core/Vertx.java +++ b/src/main/java/io/vertx/core/Vertx.java @@ -35,6 +35,7 @@ import io.vertx.core.spi.VerticleFactory; import java.util.Set; +import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; @@ -445,15 +446,15 @@ default Future deployVerticle(String name) { *

* Executes the blocking code in the handler {@code blockingCodeHandler} using a thread from the worker pool. *

- * When the code is complete the handler {@code resultHandler} will be called with the result on the original context - * (e.g. on the original event loop of the caller). + * The returned future will be completed with the result on the original context (i.e. on the original event loop of the caller) + * or failed when the handler throws an exception. *

* A {@code Future} instance is passed into {@code blockingCodeHandler}. When the blocking code successfully completes, * the handler should call the {@link Promise#complete} or {@link Promise#complete(Object)} method, or the {@link Promise#fail} * method if it failed. *

* In the {@code blockingCodeHandler} the current context remains the original context and therefore any task - * scheduled in the {@code blockingCodeHandler} will be executed on the this context and not on the worker thread. + * scheduled in the {@code blockingCodeHandler} will be executed on this context and not on the worker thread. *

* The blocking code should block for a reasonable amount of time (i.e no more than a few seconds). Long blocking operations * or polling operations (i.e a thread that spin in a loop polling events in a blocking fashion) are precluded. @@ -476,10 +477,51 @@ default Future deployVerticle(String name) { return context.executeBlocking(blockingCodeHandler, ordered); } + /** + * Safely execute some blocking code. + *

+ * Executes the blocking code in the handler {@code blockingCodeHandler} using a thread from the worker pool. + *

+ * The returned future will be completed with the result on the original context (i.e. on the original event loop of the caller) + * or failed when the handler throws an exception. + *

+ * In the {@code blockingCodeHandler} the current context remains the original context and therefore any task + * scheduled in the {@code blockingCodeHandler} will be executed on this context and not on the worker thread. + *

+ * The blocking code should block for a reasonable amount of time (i.e no more than a few seconds). Long blocking operations + * or polling operations (i.e a thread that spin in a loop polling events in a blocking fashion) are precluded. + *

+ * When the blocking operation lasts more than the 10 seconds, a message will be printed on the console by the + * blocked thread checker. + *

+ * Long blocking operations should use a dedicated thread managed by the application, which can interact with + * verticles using the event-bus or {@link Context#runOnContext(Handler)} + * + * @param blockingCodeHandler handler representing the blocking code to run + * @param ordered if true then if executeBlocking is called several times on the same context, the executions + * for that context will be executed serially, not in parallel. if false then they will be no ordering + * guarantees + * @param the type of the result + * @return a future completed when the blocking code is complete + */ + @GenIgnore(GenIgnore.PERMITTED_TYPE) + default Future<@Nullable T> executeBlocking(Callable blockingCodeHandler, boolean ordered) { + Context context = getOrCreateContext(); + return context.executeBlocking(blockingCodeHandler, ordered); + } + /** * Like {@link #executeBlocking(Handler, boolean)} called with ordered = true. */ - default Future executeBlocking(Handler> blockingCodeHandler) { + default Future<@Nullable T> executeBlocking(Handler> blockingCodeHandler) { + return executeBlocking(blockingCodeHandler, true); + } + + /** + * Like {@link #executeBlocking(Callable, boolean)} called with ordered = true. + */ + @GenIgnore(GenIgnore.PERMITTED_TYPE) + default Future<@Nullable T> executeBlocking(Callable blockingCodeHandler) { return executeBlocking(blockingCodeHandler, true); } diff --git a/src/main/java/io/vertx/core/WorkerExecutor.java b/src/main/java/io/vertx/core/WorkerExecutor.java index 804d19fac7f..98dcf843931 100644 --- a/src/main/java/io/vertx/core/WorkerExecutor.java +++ b/src/main/java/io/vertx/core/WorkerExecutor.java @@ -11,10 +11,13 @@ package io.vertx.core; +import io.vertx.codegen.annotations.GenIgnore; import io.vertx.codegen.annotations.Nullable; import io.vertx.codegen.annotations.VertxGen; import io.vertx.core.metrics.Measured; +import java.util.concurrent.Callable; + /** * An executor for executing blocking code in Vert.x .

* @@ -31,15 +34,15 @@ public interface WorkerExecutor extends Measured { *

* Executes the blocking code in the handler {@code blockingCodeHandler} using a thread from the worker pool. *

- * When the code is complete the handler {@code resultHandler} will be called with the result on the original context - * (i.e. on the original event loop of the caller). + * The returned future will be completed with the result on the original context (i.e. on the original event loop of the caller) + * or failed when the handler throws an exception. *

* A {@code Future} instance is passed into {@code blockingCodeHandler}. When the blocking code successfully completes, * the handler should call the {@link Promise#complete} or {@link Promise#complete(Object)} method, or the {@link Promise#fail} * method if it failed. *

* In the {@code blockingCodeHandler} the current context remains the original context and therefore any task - * scheduled in the {@code blockingCodeHandler} will be executed on the this context and not on the worker thread. + * scheduled in the {@code blockingCodeHandler} will be executed on this context and not on the worker thread. * * @param blockingCodeHandler handler representing the blocking code to run * @param ordered if true then if executeBlocking is called several times on the same context, the executions @@ -50,6 +53,27 @@ public interface WorkerExecutor extends Measured { */ Future<@Nullable T> executeBlocking(Handler> blockingCodeHandler, boolean ordered); + /** + * Safely execute some blocking code. + *

+ * Executes the blocking code in the handler {@code blockingCodeHandler} using a thread from the worker pool. + *

+ * The returned future will be completed with the result on the original context (i.e. on the original event loop of the caller) + * or failed when the handler throws an exception. + *

+ * In the {@code blockingCodeHandler} the current context remains the original context and therefore any task + * scheduled in the {@code blockingCodeHandler} will be executed on this context and not on the worker thread. + * + * @param blockingCodeHandler handler representing the blocking code to run + * @param ordered if true then if executeBlocking is called several times on the same context, the executions + * for that context will be executed serially, not in parallel. if false then they will be no ordering + * guarantees + * @param the type of the result + * @return a future notified with the result + */ + @GenIgnore(GenIgnore.PERMITTED_TYPE) + Future<@Nullable T> executeBlocking(Callable blockingCodeHandler, boolean ordered); + /** * Like {@link #executeBlocking(Handler, boolean)} called with ordered = true. */ @@ -57,6 +81,14 @@ default Future executeBlocking(Handler> blockingCodeHandler) { return executeBlocking(blockingCodeHandler, true); } + /** + * Like {@link #executeBlocking(Callable, boolean)} called with ordered = true. + */ + @GenIgnore(GenIgnore.PERMITTED_TYPE) + default Future executeBlocking(Callable blockingCodeHandler) { + return executeBlocking(blockingCodeHandler, true); + } + /** * Close the executor. */ diff --git a/src/main/java/io/vertx/core/impl/ContextBase.java b/src/main/java/io/vertx/core/impl/ContextBase.java index ba34949eaa5..5089f01250f 100644 --- a/src/main/java/io/vertx/core/impl/ContextBase.java +++ b/src/main/java/io/vertx/core/impl/ContextBase.java @@ -12,17 +12,16 @@ package io.vertx.core.impl; import io.netty.channel.EventLoop; +import io.vertx.codegen.annotations.Nullable; import io.vertx.core.*; +import io.vertx.core.Future; import io.vertx.core.impl.logging.Logger; import io.vertx.core.impl.logging.LoggerFactory; import io.vertx.core.json.JsonObject; import io.vertx.core.spi.metrics.PoolMetrics; import io.vertx.core.spi.tracing.VertxTracer; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.Executor; -import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.*; /** * A base class for {@link Context} implementations. @@ -97,22 +96,87 @@ public Future executeBlockingInternal(Handler> action) { return executeBlocking(this, action, internalWorkerPool, internalOrderedTasks); } + @Override + public Future executeBlockingInternal(Callable action) { + return executeBlocking(this, action, internalWorkerPool, internalOrderedTasks); + } + @Override public Future executeBlockingInternal(Handler> action, boolean ordered) { return executeBlocking(this, action, internalWorkerPool, ordered ? internalOrderedTasks : null); } + @Override + public Future executeBlockingInternal(Callable action, boolean ordered) { + return executeBlocking(this, action, internalWorkerPool, ordered ? internalOrderedTasks : null); + } + @Override public Future executeBlocking(Handler> blockingCodeHandler, boolean ordered) { return executeBlocking(this, blockingCodeHandler, workerPool, ordered ? orderedTasks : null); } + @Override + public Future executeBlocking(Callable blockingCodeHandler, boolean ordered) { + return executeBlocking(this, blockingCodeHandler, workerPool, ordered ? orderedTasks : null); + } + + @Override + public boolean isEventLoopContext() { + return false; + } + + @Override + public boolean isWorkerContext() { + return false; + } + + @Override + public Executor executor() { + return null; + } + + @Override + public boolean inThread() { + return false; + } + @Override public Future executeBlocking(Handler> blockingCodeHandler, TaskQueue queue) { return executeBlocking(this, blockingCodeHandler, workerPool, queue); } + @Override + public Future executeBlocking(Callable blockingCodeHandler, TaskQueue queue) { + return executeBlocking(this, blockingCodeHandler, workerPool, queue); + } + + static Future executeBlocking(ContextInternal context, Callable blockingCodeHandler, + WorkerPool workerPool, TaskQueue queue) { + return internalExecuteBlocking(context, promise -> { + T result; + try { + result = blockingCodeHandler.call(); + } catch (Throwable e) { + promise.fail(e); + return; + } + promise.complete(result); + }, workerPool, queue); + } + static Future executeBlocking(ContextInternal context, Handler> blockingCodeHandler, + WorkerPool workerPool, TaskQueue queue) { + return internalExecuteBlocking(context, promise -> { + try { + blockingCodeHandler.handle(promise); + } catch (Throwable e) { + promise.tryFail(e); + } + }, workerPool, queue); + } + + private static Future internalExecuteBlocking(ContextInternal context, Handler> blockingCodeHandler, WorkerPool workerPool, TaskQueue queue) { PoolMetrics metrics = workerPool.metrics(); Object queueMetric = metrics != null ? metrics.submitted() : null; @@ -124,13 +188,7 @@ static Future executeBlocking(ContextInternal context, Handler if (metrics != null) { execMetric = metrics.begin(queueMetric); } - context.dispatch(promise, f -> { - try { - blockingCodeHandler.handle(promise); - } catch (Throwable e) { - promise.tryFail(e); - } - }); + context.dispatch(promise, blockingCodeHandler); if (metrics != null) { metrics.end(execMetric, fut.succeeded()); } diff --git a/src/main/java/io/vertx/core/impl/ContextInternal.java b/src/main/java/io/vertx/core/impl/ContextInternal.java index f04dfa8d18b..4cfafccfb69 100644 --- a/src/main/java/io/vertx/core/impl/ContextInternal.java +++ b/src/main/java/io/vertx/core/impl/ContextInternal.java @@ -19,6 +19,7 @@ import io.vertx.core.impl.future.SucceededFuture; import io.vertx.core.spi.tracing.VertxTracer; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @@ -123,16 +124,22 @@ default Future failedFuture(String message) { */ Future executeBlocking(Handler> blockingCodeHandler, TaskQueue queue); + Future executeBlocking(Callable blockingCodeHandler, TaskQueue queue); + /** * Execute an internal task on the internal blocking ordered executor. */ Future executeBlockingInternal(Handler> action); + Future executeBlockingInternal(Callable action); + /** * Execute an internal task on the internal blocking ordered executor. */ Future executeBlockingInternal(Handler> action, boolean ordered); + Future executeBlockingInternal(Callable action, boolean ordered); + /** * @return the deployment associated with this context or {@code null} */ diff --git a/src/main/java/io/vertx/core/impl/DuplicatedContext.java b/src/main/java/io/vertx/core/impl/DuplicatedContext.java index 9484eb3d46f..922d06ee44d 100644 --- a/src/main/java/io/vertx/core/impl/DuplicatedContext.java +++ b/src/main/java/io/vertx/core/impl/DuplicatedContext.java @@ -18,6 +18,7 @@ import io.vertx.core.json.JsonObject; import io.vertx.core.spi.tracing.VertxTracer; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Executor; @@ -128,21 +129,41 @@ public final Future executeBlockingInternal(Handler> action) { return ContextBase.executeBlocking(this, action, delegate.internalWorkerPool, delegate.internalOrderedTasks); } + @Override + public Future executeBlockingInternal(Callable action) { + return ContextBase.executeBlocking(this, action, delegate.internalWorkerPool, delegate.internalOrderedTasks); + } + @Override public final Future executeBlockingInternal(Handler> action, boolean ordered) { return ContextBase.executeBlocking(this, action, delegate.internalWorkerPool, ordered ? delegate.internalOrderedTasks : null); } + @Override + public Future executeBlockingInternal(Callable action, boolean ordered) { + return ContextBase.executeBlocking(this, action, delegate.internalWorkerPool, ordered ? delegate.internalOrderedTasks : null); + } + @Override public final Future executeBlocking(Handler> action, boolean ordered) { return ContextBase.executeBlocking(this, action, delegate.workerPool, ordered ? delegate.orderedTasks : null); } + @Override + public final Future executeBlocking(Callable blockingCodeHandler, boolean ordered) { + return ContextBase.executeBlocking(this, blockingCodeHandler, delegate.workerPool, ordered ? delegate.orderedTasks : null); + } + @Override public final Future executeBlocking(Handler> blockingCodeHandler, TaskQueue queue) { return ContextBase.executeBlocking(this, blockingCodeHandler, delegate.workerPool, queue); } + @Override + public final Future executeBlocking(Callable blockingCodeHandler, TaskQueue queue) { + return ContextBase.executeBlocking(this, blockingCodeHandler, delegate.workerPool, queue); + } + @Override public final void runOnContext(Handler action) { delegate.runOnContext(this, action); diff --git a/src/main/java/io/vertx/core/impl/NoStackTraceException.java b/src/main/java/io/vertx/core/impl/NoStackTraceException.java new file mode 100644 index 00000000000..0cded0be7d2 --- /dev/null +++ b/src/main/java/io/vertx/core/impl/NoStackTraceException.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011-2023 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.VertxException; + +/** + * @author Julien Viet + */ +public class NoStackTraceException extends VertxException { + + public NoStackTraceException(String message) { + super(message, null, true); + } + + public NoStackTraceException(Throwable cause) { + super(cause, true); + } +} diff --git a/src/main/java/io/vertx/core/impl/VertxInternal.java b/src/main/java/io/vertx/core/impl/VertxInternal.java index dfc545de694..cd32d32f5ff 100644 --- a/src/main/java/io/vertx/core/impl/VertxInternal.java +++ b/src/main/java/io/vertx/core/impl/VertxInternal.java @@ -32,6 +32,7 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Map; +import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.function.Function; @@ -138,11 +139,21 @@ default Future executeBlockingInternal(Handler> blockingCodeHa return context.executeBlockingInternal(blockingCodeHandler); } + default Future executeBlockingInternal(Callable blockingCodeHandler) { + ContextInternal context = getOrCreateContext(); + return context.executeBlockingInternal(blockingCodeHandler); + } + default Future executeBlockingInternal(Handler> blockingCodeHandler, boolean ordered) { ContextInternal context = getOrCreateContext(); return context.executeBlockingInternal(blockingCodeHandler, ordered); } + default Future executeBlockingInternal(Callable blockingCodeHandler, boolean ordered) { + ContextInternal context = getOrCreateContext(); + return context.executeBlockingInternal(blockingCodeHandler, ordered); + } + ClusterManager getClusterManager(); HAManager haManager(); diff --git a/src/main/java/io/vertx/core/impl/VertxWrapper.java b/src/main/java/io/vertx/core/impl/VertxWrapper.java index 6f7d6bae5d7..55a11cce96a 100644 --- a/src/main/java/io/vertx/core/impl/VertxWrapper.java +++ b/src/main/java/io/vertx/core/impl/VertxWrapper.java @@ -53,6 +53,7 @@ import java.net.InetSocketAddress; import java.util.Map; import java.util.Set; +import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.function.Supplier; @@ -252,11 +253,21 @@ public Future executeBlocking(Handler> blockingCodeHandler, bo return delegate.executeBlocking(blockingCodeHandler, ordered); } + @Override + public Future executeBlocking(Callable blockingCodeHandler, boolean ordered) { + return delegate.executeBlockingInternal(blockingCodeHandler, ordered); + } + @Override public Future executeBlocking(Handler> blockingCodeHandler) { return delegate.executeBlocking(blockingCodeHandler); } + @Override + public Future executeBlocking(Callable blockingCodeHandler) { + return delegate.executeBlockingInternal(blockingCodeHandler); + } + @Override public EventLoopGroup nettyEventLoopGroup() { return delegate.nettyEventLoopGroup(); @@ -437,11 +448,21 @@ public Future executeBlockingInternal(Handler> blockingCodeHan return delegate.executeBlockingInternal(blockingCodeHandler); } + @Override + public Future executeBlockingInternal(Callable blockingCodeHandler) { + return delegate.executeBlockingInternal(blockingCodeHandler); + } + @Override public Future executeBlockingInternal(Handler> blockingCodeHandler, boolean ordered) { return delegate.executeBlockingInternal(blockingCodeHandler, ordered); } + @Override + public Future executeBlockingInternal(Callable blockingCodeHandler, boolean ordered) { + return delegate.executeBlockingInternal(blockingCodeHandler, ordered); + } + @Override public ClusterManager getClusterManager() { return delegate.getClusterManager(); diff --git a/src/main/java/io/vertx/core/impl/WorkerExecutorImpl.java b/src/main/java/io/vertx/core/impl/WorkerExecutorImpl.java index 744fe6f7273..02548ccc8f2 100644 --- a/src/main/java/io/vertx/core/impl/WorkerExecutorImpl.java +++ b/src/main/java/io/vertx/core/impl/WorkerExecutorImpl.java @@ -18,6 +18,7 @@ import io.vertx.core.spi.metrics.PoolMetrics; import java.lang.ref.Cleaner; +import java.util.concurrent.Callable; /** * @author Julien Viet @@ -62,6 +63,13 @@ public WorkerPool getPool() { return ContextBase.executeBlocking(context, blockingCodeHandler, pool, ordered ? impl.orderedTasks : null); } + @Override + public Future<@Nullable T> executeBlocking(Callable blockingCodeHandler, boolean ordered) { + ContextInternal context = vertx.getOrCreateContext(); + ContextBase impl = context instanceof DuplicatedContext ? ((DuplicatedContext)context).delegate : (ContextBase) context; + return ContextBase.executeBlocking(context, blockingCodeHandler, pool, ordered ? impl.orderedTasks : null); + } + @Override public Future close() { cleanable.clean(); diff --git a/src/test/java/io/vertx/core/FakeContext.java b/src/test/java/io/vertx/core/FakeContext.java index 1d8845bc646..e5ed6edc209 100644 --- a/src/test/java/io/vertx/core/FakeContext.java +++ b/src/test/java/io/vertx/core/FakeContext.java @@ -12,6 +12,7 @@ import io.vertx.core.json.JsonObject; import io.vertx.core.spi.tracing.VertxTracer; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Executor; @@ -47,6 +48,11 @@ public boolean inThread() { return null; } + @Override + public Future<@Nullable T> executeBlocking(Callable blockingCodeHandler, boolean ordered) { + return null; + } + @Override public String deploymentID() { return null; @@ -92,16 +98,31 @@ public Future executeBlocking(Handler> blockingCodeHandler, Ta return null; } + @Override + public Future executeBlocking(Callable blockingCodeHandler, TaskQueue queue) { + return null; + } + @Override public Future executeBlockingInternal(Handler> action) { return null; } + @Override + public Future executeBlockingInternal(Callable action) { + return null; + } + @Override public Future executeBlockingInternal(Handler> action, boolean ordered) { return null; } + @Override + public Future executeBlockingInternal(Callable action, boolean ordered) { + return null; + } + @Override public Deployment getDeployment() { return null; From 281892b473c867a13c015039a02652b1ae0bbd60 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Thu, 13 Jul 2023 10:47:59 +0200 Subject: [PATCH 022/264] Remove usage of execute blocking with handler of promise --- .../vertx/core/file/impl/AsyncFileImpl.java | 21 ++++++--------- .../core/file/impl/AsyncFileLockImpl.java | 10 +++---- .../vertx/core/file/impl/FileSystemImpl.java | 12 +++------ .../java/io/vertx/core/impl/HAManager.java | 21 ++++++++------- .../java/io/vertx/core/impl/VertxImpl.java | 26 ++++++++----------- .../io/vertx/core/net/impl/SSLHelper.java | 17 ++++++------ 6 files changed, 47 insertions(+), 60 deletions(-) diff --git a/src/main/java/io/vertx/core/file/impl/AsyncFileImpl.java b/src/main/java/io/vertx/core/file/impl/AsyncFileImpl.java index 169db42de73..c2524054bd6 100644 --- a/src/main/java/io/vertx/core/file/impl/AsyncFileImpl.java +++ b/src/main/java/io/vertx/core/file/impl/AsyncFileImpl.java @@ -410,10 +410,10 @@ private void handleEnd() { private synchronized void doFlush(Handler> handler) { checkClosed(); - context.executeBlockingInternal((Promise fut) -> { + context.executeBlockingInternal(() -> { try { ch.force(false); - fut.complete(); + return null; } catch (IOException e) { throw new FileSystemException(e); } @@ -523,13 +523,9 @@ private void checkContext() { } private void doClose(Handler> handler) { - context.executeBlockingInternal(res -> { - try { - ch.close(); - res.complete(null); - } catch (IOException e) { - res.fail(e); - } + context.executeBlockingInternal(() -> { + ch.close(); + return null; }).onComplete(handler); } @@ -556,9 +552,7 @@ public long sizeBlocking() { @Override public Future size() { - return vertx.getOrCreateContext().executeBlockingInternal(prom -> { - prom.complete(sizeBlocking()); - }); + return vertx.getOrCreateContext().executeBlockingInternal(this::sizeBlocking); } @Override @@ -599,8 +593,9 @@ public void failed(Throwable t, PromiseInternal p) { @Override public Future lock(long position, long size, boolean shared) { PromiseInternal promise = vertx.promise(); - vertx.executeBlockingInternal(prom -> { + vertx.executeBlockingInternal(() -> { ch.lock(position, size, shared, promise, LOCK_COMPLETION); + return null; }).onComplete(ar -> { if (ar.failed()) { // Happens only if ch.lock throws a RuntimeException diff --git a/src/main/java/io/vertx/core/file/impl/AsyncFileLockImpl.java b/src/main/java/io/vertx/core/file/impl/AsyncFileLockImpl.java index 506a4274f5f..40bd42cbf88 100644 --- a/src/main/java/io/vertx/core/file/impl/AsyncFileLockImpl.java +++ b/src/main/java/io/vertx/core/file/impl/AsyncFileLockImpl.java @@ -59,9 +59,7 @@ public boolean isValidBlocking() { @Override public Future isValid() { - return vertx.getOrCreateContext().executeBlockingInternal(prom -> { - prom.complete(isValidBlocking()); - }); + return vertx.getOrCreateContext().executeBlockingInternal(this::isValidBlocking); } @Override @@ -75,12 +73,12 @@ public void releaseBlocking() { @Override public Future release() { - return vertx.getOrCreateContext().executeBlockingInternal(prom -> { + return vertx.getOrCreateContext().executeBlockingInternal(() -> { try { fileLock.release(); - prom.complete(); + return null; } catch (IOException e) { - prom.fail(new FileSystemException(e)); + throw new FileSystemException(e); } }); } diff --git a/src/main/java/io/vertx/core/file/impl/FileSystemImpl.java b/src/main/java/io/vertx/core/file/impl/FileSystemImpl.java index 1f960266ed4..397510713ca 100644 --- a/src/main/java/io/vertx/core/file/impl/FileSystemImpl.java +++ b/src/main/java/io/vertx/core/file/impl/FileSystemImpl.java @@ -56,6 +56,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.concurrent.Callable; import java.util.regex.Pattern; /** @@ -966,7 +967,7 @@ public FileSystemProps perform() { }; } - protected abstract class BlockingAction implements Handler> { + protected abstract class BlockingAction implements Callable { protected final ContextInternal context; @@ -982,13 +983,8 @@ public Future run() { } @Override - public void handle(Promise fut) { - try { - T result = perform(); - fut.complete(result); - } catch (Exception e) { - fut.fail(e); - } + public T call() throws Exception { + return perform(); } public abstract T perform(); diff --git a/src/main/java/io/vertx/core/impl/HAManager.java b/src/main/java/io/vertx/core/impl/HAManager.java index 842b3f485af..fb608eb66ee 100644 --- a/src/main/java/io/vertx/core/impl/HAManager.java +++ b/src/main/java/io/vertx/core/impl/HAManager.java @@ -11,6 +11,7 @@ package io.vertx.core.impl; +import io.vertx.codegen.annotations.Nullable; import io.vertx.core.*; import io.vertx.core.impl.logging.Logger; import io.vertx.core.impl.logging.LoggerFactory; @@ -263,16 +264,18 @@ public void failDuringFailover(boolean fail) { private void doDeployVerticle(final String verticleName, DeploymentOptions deploymentOptions, final Handler> doneHandler) { final Handler> wrappedHandler = ar1 -> { - vertx.executeBlocking(fut -> { - if (ar1.succeeded()) { + Future fut; + if (ar1.succeeded()) { + fut = vertx.executeBlocking(() -> { // Tell the other nodes of the cluster about the verticle for HA purposes String deploymentID = ar1.result(); addToHA(deploymentID, verticleName, deploymentOptions); - fut.complete(deploymentID); - } else { - fut.fail(ar1.cause()); - } - }, false).onComplete(ar2 -> { + return deploymentID; + }, false); + } else { + fut = (Future) ar1; + } + fut.onComplete(ar2 -> { if (doneHandler != null) { doneHandler.handle(ar2); } else if (ar2.failed()) { @@ -339,7 +342,7 @@ private synchronized void checkQuorumWhenAdded(final String nodeID, final long s checkQuorumTimerID = -1L; if (!stopped) { // This can block on a monitor so it needs to run as a worker - vertx.executeBlockingInternal(fut -> { + vertx.executeBlockingInternal(() -> { if (System.currentTimeMillis() - start > 10000) { log.warn("Timed out waiting for group information to appear"); } else { @@ -348,7 +351,7 @@ private synchronized void checkQuorumWhenAdded(final String nodeID, final long s checkQuorumWhenAdded(nodeID, start); }); } - fut.complete(); + return null; }); } }); diff --git a/src/main/java/io/vertx/core/impl/VertxImpl.java b/src/main/java/io/vertx/core/impl/VertxImpl.java index 6e83fbbd896..f74cdca5242 100644 --- a/src/main/java/io/vertx/core/impl/VertxImpl.java +++ b/src/main/java/io/vertx/core/impl/VertxImpl.java @@ -237,9 +237,9 @@ Future initClustered(VertxOptions options) { private void createHaManager(VertxOptions options, Promise initPromise) { if (options.isHAEnabled()) { - this.executeBlocking(fut -> { + this.executeBlocking(() -> { haManager = new HAManager(this, deploymentManager, verticleManager, clusterManager, clusterManager.getSyncMap(CLUSTER_MAP_NAME), options.getQuorumSize(), options.getHAGroup()); - fut.complete(haManager); + return haManager; }, false).onComplete(ar -> { if (ar.succeeded()) { startEventBus(true, initPromise); @@ -269,12 +269,12 @@ private void startEventBus(boolean haEnabled, Promise initPromise) { } private void initializeHaManager(Promise initPromise) { - this.executeBlocking(fut -> { + this.executeBlocking(() -> { // Init the manager (i.e register listener and check the quorum) // after the event bus has been fully started and updated its state // it will have also set the clustered changed view handler on the ha manager haManager.init(); - fut.complete(); + return null; }, false).onComplete(initPromise); } @@ -604,9 +604,9 @@ public synchronized Future close() { .close() .transform(ar -> deploymentManager.undeployAll()); if (haManager != null) { - fut = fut.transform(ar -> executeBlocking(res -> { + fut = fut.transform(ar -> executeBlocking(() -> { haManager.stop(); - res.complete(); + return null; }, false)); } fut = fut @@ -679,9 +679,9 @@ public Future undeploy(String deploymentID) { Future future; HAManager haManager = haManager(); if (haManager != null) { - future = this.executeBlocking(fut -> { + future = this.executeBlocking(() -> { haManager.removeFromHA(deploymentID); - fut.complete(); + return null; }, false); } else { future = getOrCreateContext().succeededFuture(); @@ -787,13 +787,9 @@ public BlockedThreadChecker blockedThreadChecker() { @SuppressWarnings("unchecked") private void deleteCacheDirAndShutdown(Promise promise) { - executeBlockingInternal(fut -> { - try { - fileResolver.close(); - fut.complete(); - } catch (IOException e) { - fut.tryFail(e); - } + executeBlockingInternal(() -> { + fileResolver.close(); + return null; }).onComplete(ar -> { workerPool.close(); internalWorkerPool.close(); diff --git a/src/main/java/io/vertx/core/net/impl/SSLHelper.java b/src/main/java/io/vertx/core/net/impl/SSLHelper.java index 1fb4fc0abed..6c7efaea5b4 100755 --- a/src/main/java/io/vertx/core/net/impl/SSLHelper.java +++ b/src/main/java/io/vertx/core/net/impl/SSLHelper.java @@ -19,6 +19,7 @@ import io.vertx.core.buffer.Buffer; import io.vertx.core.http.ClientAuth; import io.vertx.core.impl.ContextInternal; +import io.vertx.core.impl.NoStackTraceException; import io.vertx.core.net.ClientOptionsBase; import io.vertx.core.net.JdkSSLEngineOptions; import io.vertx.core.net.KeyCertOptions; @@ -240,7 +241,7 @@ private Future build(SSLOptions sslOptions, ContextInternal ctx) { if (keyCertOptions != null || trustOptions != null || trustAll || ssl) { Promise promise = Promise.promise(); sslContextFactorySupplier = promise.future(); - ctx.executeBlockingInternal(p -> { + ctx.executeBlockingInternal(() -> { try { if (sslOptions.getKeyCertOptions() != null) { keyManagerFactory = sslOptions.getKeyCertOptions().getKeyManagerFactory(ctx.owner()); @@ -267,15 +268,14 @@ private Future build(SSLOptions sslOptions, ContextInternal ctx) { crls.addAll(certificatefactory.generateCRLs(new ByteArrayInputStream(crlValue.getBytes()))); } } catch (Exception e) { - p.fail(e); - return; + throw e; } if (client || sslOptions.getKeyCertOptions() != null) { - p.complete(); + return null; } else { - p.fail("Key/certificate is mandatory for SSL"); + throw new NoStackTraceException("Key/certificate is mandatory for SSL"); } - }).compose(v2 -> ctx.executeBlockingInternal(p -> { + }).compose(v2 -> ctx.executeBlockingInternal(() -> { Supplier supplier; boolean useWorkerPool; try { @@ -283,10 +283,9 @@ private Future build(SSLOptions sslOptions, ContextInternal ctx) { supplier = resolvedEngineOptions::sslContextFactory; useWorkerPool = resolvedEngineOptions.getUseWorkerThread(); } catch (Exception e) { - p.fail(e); - return; + throw e; } - p.complete(new EngineConfig(sslOptions, supplier, useWorkerPool)); + return new EngineConfig(sslOptions, supplier, useWorkerPool); })).onComplete(promise); } else { sslContextFactorySupplier = Future.succeededFuture(new EngineConfig(sslOptions, () -> new DefaultSslContextFactory(SslProvider.JDK, false), SSLEngineOptions.DEFAULT_USE_WORKER_POOL)); From 0e7f251e065b3b1936b1eb52552c9f374f618539 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Thu, 13 Jul 2023 10:56:57 +0200 Subject: [PATCH 023/264] Remove execute blocking with handler of promise from API --- src/main/java/io/vertx/core/Context.java | 40 ----------------- src/main/java/io/vertx/core/Vertx.java | 43 ------------------- .../java/io/vertx/core/WorkerExecutor.java | 31 ------------- .../java/io/vertx/core/impl/ContextBase.java | 20 --------- .../io/vertx/core/impl/ContextInternal.java | 8 +--- .../io/vertx/core/impl/DuplicatedContext.java | 20 --------- .../io/vertx/core/impl/VertxInternal.java | 10 ----- .../java/io/vertx/core/impl/VertxWrapper.java | 20 --------- .../vertx/core/impl/WorkerExecutorImpl.java | 7 --- 9 files changed, 1 insertion(+), 198 deletions(-) diff --git a/src/main/java/io/vertx/core/Context.java b/src/main/java/io/vertx/core/Context.java index 80651ad5d66..38784cfe202 100644 --- a/src/main/java/io/vertx/core/Context.java +++ b/src/main/java/io/vertx/core/Context.java @@ -101,36 +101,6 @@ static boolean isOnVertxThread() { */ void runOnContext(Handler action); - /** - * Safely execute some blocking code. - *

- * Executes the blocking code in the handler {@code blockingCodeHandler} using a thread from the worker pool. - *

- * The returned future will be completed with the result on the original context (i.e. on the original event loop of the caller) - * or failed when the handler throws an exception. - *

- * A {@code Future} instance is passed into {@code blockingCodeHandler}. When the blocking code successfully completes, - * the handler should call the {@link Promise#complete} or {@link Promise#complete(Object)} method, or the {@link Promise#fail} - * method if it failed. - *

- * The blocking code should block for a reasonable amount of time (i.e no more than a few seconds). Long blocking operations - * or polling operations (i.e a thread that spin in a loop polling events in a blocking fashion) are precluded. - *

- * When the blocking operation lasts more than the 10 seconds, a message will be printed on the console by the - * blocked thread checker. - *

- * Long blocking operations should use a dedicated thread managed by the application, which can interact with - * verticles using the event-bus or {@link Context#runOnContext(Handler)} - * - * @param blockingCodeHandler handler representing the blocking code to run - * @param ordered if true then if executeBlocking is called several times on the same context, the executions - * for that context will be executed serially, not in parallel. if false then they will be no ordering - * guarantees - * @param the type of the result - * @return a future completed when the blocking code is complete - */ - Future<@Nullable T> executeBlocking(Handler> blockingCodeHandler, boolean ordered); - /** * Safely execute some blocking code. *

@@ -158,16 +128,6 @@ static boolean isOnVertxThread() { @GenIgnore(GenIgnore.PERMITTED_TYPE) Future<@Nullable T> executeBlocking(Callable blockingCodeHandler, boolean ordered); - /** - * Invoke {@link #executeBlocking(Handler, boolean)} with order = true. - * @param blockingCodeHandler handler representing the blocking code to run - * @param the type of the result - * @return a future completed when the blocking code is complete - */ - default Future<@Nullable T> executeBlocking(Handler> blockingCodeHandler) { - return executeBlocking(blockingCodeHandler, true); - } - /** * Invoke {@link #executeBlocking(Callable, boolean)} with order = true. * @param blockingCodeHandler handler representing the blocking code to run diff --git a/src/main/java/io/vertx/core/Vertx.java b/src/main/java/io/vertx/core/Vertx.java index 4ad9684837b..52b807003b8 100644 --- a/src/main/java/io/vertx/core/Vertx.java +++ b/src/main/java/io/vertx/core/Vertx.java @@ -441,42 +441,6 @@ default Future deployVerticle(String name) { */ boolean isClustered(); - /** - * Safely execute some blocking code. - *

- * Executes the blocking code in the handler {@code blockingCodeHandler} using a thread from the worker pool. - *

- * The returned future will be completed with the result on the original context (i.e. on the original event loop of the caller) - * or failed when the handler throws an exception. - *

- * A {@code Future} instance is passed into {@code blockingCodeHandler}. When the blocking code successfully completes, - * the handler should call the {@link Promise#complete} or {@link Promise#complete(Object)} method, or the {@link Promise#fail} - * method if it failed. - *

- * In the {@code blockingCodeHandler} the current context remains the original context and therefore any task - * scheduled in the {@code blockingCodeHandler} will be executed on this context and not on the worker thread. - *

- * The blocking code should block for a reasonable amount of time (i.e no more than a few seconds). Long blocking operations - * or polling operations (i.e a thread that spin in a loop polling events in a blocking fashion) are precluded. - *

- * When the blocking operation lasts more than the 10 seconds, a message will be printed on the console by the - * blocked thread checker. - *

- * Long blocking operations should use a dedicated thread managed by the application, which can interact with - * verticles using the event-bus or {@link Context#runOnContext(Handler)} - * - * @param blockingCodeHandler handler representing the blocking code to run - * @param ordered if true then if executeBlocking is called several times on the same context, the executions - * for that context will be executed serially, not in parallel. if false then they will be no ordering - * guarantees - * @param the type of the result - * @return a future completed when the blocking code is complete - */ - default Future<@Nullable T> executeBlocking(Handler> blockingCodeHandler, boolean ordered) { - Context context = getOrCreateContext(); - return context.executeBlocking(blockingCodeHandler, ordered); - } - /** * Safely execute some blocking code. *

@@ -510,13 +474,6 @@ default Future deployVerticle(String name) { return context.executeBlocking(blockingCodeHandler, ordered); } - /** - * Like {@link #executeBlocking(Handler, boolean)} called with ordered = true. - */ - default Future<@Nullable T> executeBlocking(Handler> blockingCodeHandler) { - return executeBlocking(blockingCodeHandler, true); - } - /** * Like {@link #executeBlocking(Callable, boolean)} called with ordered = true. */ diff --git a/src/main/java/io/vertx/core/WorkerExecutor.java b/src/main/java/io/vertx/core/WorkerExecutor.java index 98dcf843931..6b50d1a68fe 100644 --- a/src/main/java/io/vertx/core/WorkerExecutor.java +++ b/src/main/java/io/vertx/core/WorkerExecutor.java @@ -29,30 +29,6 @@ @VertxGen public interface WorkerExecutor extends Measured { - /** - * Safely execute some blocking code. - *

- * Executes the blocking code in the handler {@code blockingCodeHandler} using a thread from the worker pool. - *

- * The returned future will be completed with the result on the original context (i.e. on the original event loop of the caller) - * or failed when the handler throws an exception. - *

- * A {@code Future} instance is passed into {@code blockingCodeHandler}. When the blocking code successfully completes, - * the handler should call the {@link Promise#complete} or {@link Promise#complete(Object)} method, or the {@link Promise#fail} - * method if it failed. - *

- * In the {@code blockingCodeHandler} the current context remains the original context and therefore any task - * scheduled in the {@code blockingCodeHandler} will be executed on this context and not on the worker thread. - * - * @param blockingCodeHandler handler representing the blocking code to run - * @param ordered if true then if executeBlocking is called several times on the same context, the executions - * for that context will be executed serially, not in parallel. if false then they will be no ordering - * guarantees - * @param the type of the result - * @return a future notified with the result - */ - Future<@Nullable T> executeBlocking(Handler> blockingCodeHandler, boolean ordered); - /** * Safely execute some blocking code. *

@@ -74,13 +50,6 @@ public interface WorkerExecutor extends Measured { @GenIgnore(GenIgnore.PERMITTED_TYPE) Future<@Nullable T> executeBlocking(Callable blockingCodeHandler, boolean ordered); - /** - * Like {@link #executeBlocking(Handler, boolean)} called with ordered = true. - */ - default Future executeBlocking(Handler> blockingCodeHandler) { - return executeBlocking(blockingCodeHandler, true); - } - /** * Like {@link #executeBlocking(Callable, boolean)} called with ordered = true. */ diff --git a/src/main/java/io/vertx/core/impl/ContextBase.java b/src/main/java/io/vertx/core/impl/ContextBase.java index 5089f01250f..349db5c9aef 100644 --- a/src/main/java/io/vertx/core/impl/ContextBase.java +++ b/src/main/java/io/vertx/core/impl/ContextBase.java @@ -91,31 +91,16 @@ public VertxInternal owner() { return owner; } - @Override - public Future executeBlockingInternal(Handler> action) { - return executeBlocking(this, action, internalWorkerPool, internalOrderedTasks); - } - @Override public Future executeBlockingInternal(Callable action) { return executeBlocking(this, action, internalWorkerPool, internalOrderedTasks); } - @Override - public Future executeBlockingInternal(Handler> action, boolean ordered) { - return executeBlocking(this, action, internalWorkerPool, ordered ? internalOrderedTasks : null); - } - @Override public Future executeBlockingInternal(Callable action, boolean ordered) { return executeBlocking(this, action, internalWorkerPool, ordered ? internalOrderedTasks : null); } - @Override - public Future executeBlocking(Handler> blockingCodeHandler, boolean ordered) { - return executeBlocking(this, blockingCodeHandler, workerPool, ordered ? orderedTasks : null); - } - @Override public Future executeBlocking(Callable blockingCodeHandler, boolean ordered) { return executeBlocking(this, blockingCodeHandler, workerPool, ordered ? orderedTasks : null); @@ -141,11 +126,6 @@ public boolean inThread() { return false; } - @Override - public Future executeBlocking(Handler> blockingCodeHandler, TaskQueue queue) { - return executeBlocking(this, blockingCodeHandler, workerPool, queue); - } - @Override public Future executeBlocking(Callable blockingCodeHandler, TaskQueue queue) { return executeBlocking(this, blockingCodeHandler, workerPool, queue); diff --git a/src/main/java/io/vertx/core/impl/ContextInternal.java b/src/main/java/io/vertx/core/impl/ContextInternal.java index 4cfafccfb69..bd0248c3c3e 100644 --- a/src/main/java/io/vertx/core/impl/ContextInternal.java +++ b/src/main/java/io/vertx/core/impl/ContextInternal.java @@ -119,25 +119,19 @@ default Future failedFuture(String message) { } /** - * Like {@link #executeBlocking(Handler, boolean)} but uses the {@code queue} to order the tasks instead + * Like {@link #executeBlocking(Callable, boolean)} but uses the {@code queue} to order the tasks instead * of the internal queue of this context. */ - Future executeBlocking(Handler> blockingCodeHandler, TaskQueue queue); - Future executeBlocking(Callable blockingCodeHandler, TaskQueue queue); /** * Execute an internal task on the internal blocking ordered executor. */ - Future executeBlockingInternal(Handler> action); - Future executeBlockingInternal(Callable action); /** * Execute an internal task on the internal blocking ordered executor. */ - Future executeBlockingInternal(Handler> action, boolean ordered); - Future executeBlockingInternal(Callable action, boolean ordered); /** diff --git a/src/main/java/io/vertx/core/impl/DuplicatedContext.java b/src/main/java/io/vertx/core/impl/DuplicatedContext.java index 922d06ee44d..eacb3d0e3a6 100644 --- a/src/main/java/io/vertx/core/impl/DuplicatedContext.java +++ b/src/main/java/io/vertx/core/impl/DuplicatedContext.java @@ -124,41 +124,21 @@ public final ConcurrentMap localContextData() { } } - @Override - public final Future executeBlockingInternal(Handler> action) { - return ContextBase.executeBlocking(this, action, delegate.internalWorkerPool, delegate.internalOrderedTasks); - } - @Override public Future executeBlockingInternal(Callable action) { return ContextBase.executeBlocking(this, action, delegate.internalWorkerPool, delegate.internalOrderedTasks); } - @Override - public final Future executeBlockingInternal(Handler> action, boolean ordered) { - return ContextBase.executeBlocking(this, action, delegate.internalWorkerPool, ordered ? delegate.internalOrderedTasks : null); - } - @Override public Future executeBlockingInternal(Callable action, boolean ordered) { return ContextBase.executeBlocking(this, action, delegate.internalWorkerPool, ordered ? delegate.internalOrderedTasks : null); } - @Override - public final Future executeBlocking(Handler> action, boolean ordered) { - return ContextBase.executeBlocking(this, action, delegate.workerPool, ordered ? delegate.orderedTasks : null); - } - @Override public final Future executeBlocking(Callable blockingCodeHandler, boolean ordered) { return ContextBase.executeBlocking(this, blockingCodeHandler, delegate.workerPool, ordered ? delegate.orderedTasks : null); } - @Override - public final Future executeBlocking(Handler> blockingCodeHandler, TaskQueue queue) { - return ContextBase.executeBlocking(this, blockingCodeHandler, delegate.workerPool, queue); - } - @Override public final Future executeBlocking(Callable blockingCodeHandler, TaskQueue queue) { return ContextBase.executeBlocking(this, blockingCodeHandler, delegate.workerPool, queue); diff --git a/src/main/java/io/vertx/core/impl/VertxInternal.java b/src/main/java/io/vertx/core/impl/VertxInternal.java index cd32d32f5ff..fdcd5a595b2 100644 --- a/src/main/java/io/vertx/core/impl/VertxInternal.java +++ b/src/main/java/io/vertx/core/impl/VertxInternal.java @@ -134,21 +134,11 @@ default C createSharedResource(String resourceKey, String resourceName, Clos File resolveFile(String fileName); - default Future executeBlockingInternal(Handler> blockingCodeHandler) { - ContextInternal context = getOrCreateContext(); - return context.executeBlockingInternal(blockingCodeHandler); - } - default Future executeBlockingInternal(Callable blockingCodeHandler) { ContextInternal context = getOrCreateContext(); return context.executeBlockingInternal(blockingCodeHandler); } - default Future executeBlockingInternal(Handler> blockingCodeHandler, boolean ordered) { - ContextInternal context = getOrCreateContext(); - return context.executeBlockingInternal(blockingCodeHandler, ordered); - } - default Future executeBlockingInternal(Callable blockingCodeHandler, boolean ordered) { ContextInternal context = getOrCreateContext(); return context.executeBlockingInternal(blockingCodeHandler, ordered); diff --git a/src/main/java/io/vertx/core/impl/VertxWrapper.java b/src/main/java/io/vertx/core/impl/VertxWrapper.java index 55a11cce96a..42452468500 100644 --- a/src/main/java/io/vertx/core/impl/VertxWrapper.java +++ b/src/main/java/io/vertx/core/impl/VertxWrapper.java @@ -248,21 +248,11 @@ public boolean isClustered() { return delegate.isClustered(); } - @Override - public Future executeBlocking(Handler> blockingCodeHandler, boolean ordered) { - return delegate.executeBlocking(blockingCodeHandler, ordered); - } - @Override public Future executeBlocking(Callable blockingCodeHandler, boolean ordered) { return delegate.executeBlockingInternal(blockingCodeHandler, ordered); } - @Override - public Future executeBlocking(Handler> blockingCodeHandler) { - return delegate.executeBlocking(blockingCodeHandler); - } - @Override public Future executeBlocking(Callable blockingCodeHandler) { return delegate.executeBlockingInternal(blockingCodeHandler); @@ -443,21 +433,11 @@ public File resolveFile(String fileName) { return delegate.resolveFile(fileName); } - @Override - public Future executeBlockingInternal(Handler> blockingCodeHandler) { - return delegate.executeBlockingInternal(blockingCodeHandler); - } - @Override public Future executeBlockingInternal(Callable blockingCodeHandler) { return delegate.executeBlockingInternal(blockingCodeHandler); } - @Override - public Future executeBlockingInternal(Handler> blockingCodeHandler, boolean ordered) { - return delegate.executeBlockingInternal(blockingCodeHandler, ordered); - } - @Override public Future executeBlockingInternal(Callable blockingCodeHandler, boolean ordered) { return delegate.executeBlockingInternal(blockingCodeHandler, ordered); diff --git a/src/main/java/io/vertx/core/impl/WorkerExecutorImpl.java b/src/main/java/io/vertx/core/impl/WorkerExecutorImpl.java index 02548ccc8f2..e7660f15ea3 100644 --- a/src/main/java/io/vertx/core/impl/WorkerExecutorImpl.java +++ b/src/main/java/io/vertx/core/impl/WorkerExecutorImpl.java @@ -56,13 +56,6 @@ public WorkerPool getPool() { return pool; } - @Override - public Future<@Nullable T> executeBlocking(Handler> blockingCodeHandler, boolean ordered) { - ContextInternal context = vertx.getOrCreateContext(); - ContextBase impl = context instanceof DuplicatedContext ? ((DuplicatedContext)context).delegate : (ContextBase) context; - return ContextBase.executeBlocking(context, blockingCodeHandler, pool, ordered ? impl.orderedTasks : null); - } - @Override public Future<@Nullable T> executeBlocking(Callable blockingCodeHandler, boolean ordered) { ContextInternal context = vertx.getOrCreateContext(); From 9e41a1d74743e94fbe9690c62ad345d2a6782245 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Thu, 13 Jul 2023 11:18:27 +0200 Subject: [PATCH 024/264] Update tests --- .../vertx/core/BlockedThreadCheckerTest.java | 13 ++-- .../java/io/vertx/core/ComplexHATest.java | 4 +- src/test/java/io/vertx/core/ContextTest.java | 68 +++++++++++-------- .../core/CustomerLauncherLowMemoryTest.java | 6 +- .../java/io/vertx/core/DeploymentTest.java | 6 +- .../io/vertx/core/ExecuteBlockingTest.java | 27 +++++--- src/test/java/io/vertx/core/FakeContext.java | 20 ------ src/test/java/io/vertx/core/HATest.java | 10 +-- .../io/vertx/core/NamedWorkerPoolTest.java | 53 +++++++++------ src/test/java/io/vertx/core/VertxTest.java | 12 ++-- .../vertx/core/eventbus/EventBusTestBase.java | 10 +-- .../MessageQueueOnWorkerThreadTest.java | 16 +++-- .../io/vertx/core/file/FileSystemTest.java | 8 +-- .../core/shareddata/AsynchronousLockTest.java | 17 ++--- .../vertx/core/spi/metrics/MetricsTest.java | 18 ++--- .../io/vertx/core/spi/tracing/TracerTest.java | 2 +- .../vertx/it/ExecutorServiceFactoryTest.java | 4 +- .../test/fakecluster/FakeClusterManager.java | 8 +-- 18 files changed, 151 insertions(+), 151 deletions(-) diff --git a/src/test/java/io/vertx/core/BlockedThreadCheckerTest.java b/src/test/java/io/vertx/core/BlockedThreadCheckerTest.java index 7c56e6907ed..36cccc80469 100644 --- a/src/test/java/io/vertx/core/BlockedThreadCheckerTest.java +++ b/src/test/java/io/vertx/core/BlockedThreadCheckerTest.java @@ -129,13 +129,14 @@ public void testBlockCheckExecuteBlocking() throws Exception { Verticle verticle = new AbstractVerticle() { @Override public void start() throws InterruptedException { - vertx.executeBlocking(fut -> { + vertx.executeBlocking(() -> { try { Thread.sleep(3000); } catch (InterruptedException e) { fail(); } testComplete(); + return null; }); } }; @@ -169,13 +170,9 @@ public void testNamedWorkerPoolMaxExecuteWorkerTime() { vertx.deployVerticle(new AbstractVerticle() { @Override public void start(Promise startPromise) throws Exception { - vertx.executeBlocking(fut -> { - try { - SECONDS.sleep(5); - fut.complete(); - } catch (InterruptedException e) { - fut.fail(e); - } + vertx.executeBlocking(() -> { + SECONDS.sleep(5); + return null; }).onComplete(startPromise); } }, deploymentOptions).onComplete(onSuccess(did -> { diff --git a/src/test/java/io/vertx/core/ComplexHATest.java b/src/test/java/io/vertx/core/ComplexHATest.java index 9f2de286dd1..0798d2a52a7 100644 --- a/src/test/java/io/vertx/core/ComplexHATest.java +++ b/src/test/java/io/vertx/core/ComplexHATest.java @@ -175,9 +175,9 @@ protected void kill(int pos) { takeDeploymentSnapshots(); VertxInternal v = (VertxInternal)vertices[pos]; killedNode = pos; - v.executeBlocking(fut -> { + v.executeBlocking(() -> { v.simulateKill(); - fut.complete(); + return null; }, false).onComplete(onSuccess(v2 -> {})); } diff --git a/src/test/java/io/vertx/core/ContextTest.java b/src/test/java/io/vertx/core/ContextTest.java index 62977189554..d12d762beef 100644 --- a/src/test/java/io/vertx/core/ContextTest.java +++ b/src/test/java/io/vertx/core/ContextTest.java @@ -124,12 +124,12 @@ public void testGettingContextContextUnderContextAnotherInstanceShouldReturnDiff @Test public void testExecuteOrderedBlocking() throws Exception { Context context = vertx.getOrCreateContext(); - context.executeBlocking(f -> { + context.executeBlocking(() -> { assertTrue(Context.isOnWorkerThread()); - f.complete(1 + 2); + return 1 + 2; }).onComplete(onSuccess(r -> { assertTrue(Context.isOnEventLoopThread()); - assertEquals(r, 3); + assertEquals((int)r, 3); testComplete(); })); await(); @@ -138,13 +138,13 @@ public void testExecuteOrderedBlocking() throws Exception { @Test public void testExecuteUnorderedBlocking() throws Exception { Context context = vertx.getOrCreateContext(); - context.executeBlocking(f -> { + context.executeBlocking(() -> { assertTrue(Context.isOnWorkerThread()); - f.complete(1 + 2); + return 1 + 2; }, false) .onComplete(onSuccess(r -> { assertTrue(Context.isOnEventLoopThread()); - assertEquals(r, 3); + assertEquals((int)r, 3); testComplete(); })); await(); @@ -155,7 +155,7 @@ public void testExecuteBlockingThreadSyncComplete() throws Exception { Context context = vertx.getOrCreateContext(); context.runOnContext(v -> { Thread expected = Thread.currentThread(); - context.executeBlocking(Promise::complete).onComplete(onSuccess(r -> { + context.executeBlocking(() -> null).onComplete(onSuccess(r -> { assertSame(expected, Thread.currentThread()); testComplete(); })); @@ -168,7 +168,8 @@ public void testExecuteBlockingThreadAsyncComplete() throws Exception { Context context = vertx.getOrCreateContext(); context.runOnContext(v -> { Thread expected = Thread.currentThread(); - context.executeBlocking(fut -> { + context.executeBlocking(() -> { + CountDownLatch latch = new CountDownLatch(1); new Thread(() -> { try { // Wait some time to allow the worker thread to set the handler on the future and have the future @@ -177,8 +178,10 @@ public void testExecuteBlockingThreadAsyncComplete() throws Exception { } catch (InterruptedException e) { Thread.currentThread().interrupt(); } - fut.complete(); + latch.countDown(); }).start(); + latch.await(20, TimeUnit.SECONDS); + return null; }).onComplete(onSuccess(r -> { assertSame(context, Vertx.currentContext()); assertSame(expected, Thread.currentThread()); @@ -297,14 +300,10 @@ private void testVerticleUseDifferentOrderedExecutor(boolean worker) throws Exce vertx.deployVerticle(new AbstractVerticle() { @Override public void start() throws Exception { - vertx.executeBlocking(fut -> { + vertx.executeBlocking(() -> { latch1.countDown(); - try { - awaitLatch(latch2); - fut.complete(); - } catch (InterruptedException e) { - fut.fail(e); - } + awaitLatch(latch2); + return null; }).onComplete(onSuccess(v -> complete())); } }, new DeploymentOptions().setWorker(worker)); @@ -313,9 +312,9 @@ public void start() throws Exception { vertx.deployVerticle(new AbstractVerticle() { @Override public void start() throws Exception { - vertx.executeBlocking(fut -> { + vertx.executeBlocking(() -> { latch3.countDown(); - fut.complete(); + return null; }).onComplete(onSuccess(v -> { complete(); })); @@ -329,7 +328,7 @@ public void start() throws Exception { @Test public void testInternalExecuteBlockingWithQueue() { ContextInternal context = (ContextInternal) vertx.getOrCreateContext(); - List>>> lst = new ArrayList<>(); + List>> lst = new ArrayList<>(); for (int i = 0;i < 2;i++) { TaskQueue queue = new TaskQueue(); lst.add(task -> { @@ -339,7 +338,7 @@ public void testInternalExecuteBlockingWithQueue() { testInternalExecuteBlockingWithQueue(lst); } - public void testInternalExecuteBlockingWithQueue(List>>> lst) { + public void testInternalExecuteBlockingWithQueue(List>> lst) { AtomicReference[] current = new AtomicReference[lst.size()]; waitFor(lst.size()); for (int i = 0;i < current.length;i++) { @@ -352,7 +351,7 @@ public void testInternalExecuteBlockingWithQueue(List> task = fut -> { + Callable task = () -> { if (ival == 0) { current[jval].set(Thread.currentThread()); latch.countDown(); @@ -372,6 +371,7 @@ public void testInternalExecuteBlockingWithQueue(List { - vertx.executeBlocking(Promise::complete).onComplete(onSuccess(res -> { + vertx.executeBlocking(() -> null).onComplete(onSuccess(res -> { assertSame(duplicated, Vertx.currentContext()); latch4.countDown(); })); @@ -564,7 +564,7 @@ private void testDuplicateExecuteBlocking(Supplier supplier, bo int n = 2; List dup1 = Stream.generate(supplier).limit(n).collect(Collectors.toList()); AtomicInteger cnt = new AtomicInteger(); - List> futures = dup1.stream().map(c -> c.executeBlocking(duplicate -> { + List> futures = dup1.stream().map(c -> c.executeBlocking(() -> { assertTrue(Context.isOnWorkerThread()); int val = cnt.incrementAndGet(); if (ordered) { @@ -579,7 +579,7 @@ private void testDuplicateExecuteBlocking(Supplier supplier, bo } finally { cnt.decrementAndGet(); } - duplicate.complete(); + return null; }, ordered)).collect(Collectors.toList()); Future.all(futures).onComplete(onSuccess(v -> { testComplete(); @@ -699,15 +699,17 @@ void testEventLoopContextPromiseCompletedByAnotherEventLoopThread(Consumer p.complete("the-value")); + testEventLoopContextPromiseCompletedByWorkerThread(() -> "the-value"); } @Test public void testEventLoopContextPromiseFailedByWorkerThread() { - testEventLoopContextPromiseCompletedByWorkerThread(p -> p.fail(new Exception())); + testEventLoopContextPromiseCompletedByWorkerThread(() -> { + throw new Exception(); + }); } - private void testEventLoopContextPromiseCompletedByWorkerThread(Consumer> action) { + private void testEventLoopContextPromiseCompletedByWorkerThread(Callable action) { ContextInternal context = (ContextInternal) vertx.getOrCreateContext(); Promise promise = context.promise(); context.runOnContext(v -> { @@ -716,8 +718,16 @@ private void testEventLoopContextPromiseCompletedByWorkerThread(Consumer { - action.accept(promise); + context.executeBlocking(() -> { + String res; + try { + res = action.call(); + } catch (Exception e) { + promise.fail(e); + return null; + } + promise.tryComplete(res); + return null; }); }); await(); diff --git a/src/test/java/io/vertx/core/CustomerLauncherLowMemoryTest.java b/src/test/java/io/vertx/core/CustomerLauncherLowMemoryTest.java index 8ab83c513e1..b325a9fd85f 100644 --- a/src/test/java/io/vertx/core/CustomerLauncherLowMemoryTest.java +++ b/src/test/java/io/vertx/core/CustomerLauncherLowMemoryTest.java @@ -119,7 +119,7 @@ public Verticle() { @Override public void start() throws Exception { - vertx.>executeBlocking(prom -> { + vertx.>executeBlocking(() -> { List res = new ArrayList<>(); long l; do { @@ -129,10 +129,10 @@ public void start() throws Exception { runtime.gc(); try { Thread.sleep(100); - prom.complete(res); + return res; } catch (InterruptedException e) { Thread.currentThread().interrupt(); - prom.fail(e); + throw e; } }).onComplete(ar1 -> { if (ar1.succeeded()) { diff --git a/src/test/java/io/vertx/core/DeploymentTest.java b/src/test/java/io/vertx/core/DeploymentTest.java index ba7d0f381e5..0473a075b6b 100644 --- a/src/test/java/io/vertx/core/DeploymentTest.java +++ b/src/test/java/io/vertx/core/DeploymentTest.java @@ -1270,13 +1270,13 @@ public void testUndeployParentDuringChildDeployment() throws Exception { MyAsyncVerticle childVerticle = new MyAsyncVerticle(startPromise -> { deployLatch.countDown(); - Vertx.currentContext().executeBlocking(prom -> { + Vertx.currentContext().executeBlocking(() -> { try { undeployLatch.await(); - prom.complete(); + return null; } catch (InterruptedException e) { Thread.currentThread().interrupt(); - prom.fail(e.getMessage()); + throw e; } }).onComplete(startPromise); }, Promise::complete); diff --git a/src/test/java/io/vertx/core/ExecuteBlockingTest.java b/src/test/java/io/vertx/core/ExecuteBlockingTest.java index f72f332dfff..07ead9c73f3 100644 --- a/src/test/java/io/vertx/core/ExecuteBlockingTest.java +++ b/src/test/java/io/vertx/core/ExecuteBlockingTest.java @@ -11,10 +11,12 @@ package io.vertx.core; +import io.vertx.core.impl.NoStackTraceException; import io.vertx.test.core.VertxTestBase; import org.junit.Test; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; /** @@ -25,12 +27,12 @@ public class ExecuteBlockingTest extends VertxTestBase { @Test public void testExecuteBlockingSuccess() { - vertx.executeBlocking(future -> { + vertx.executeBlocking(() -> { try { Thread.sleep(1000); } catch (Exception ignore) { } - future.complete("done!"); + return "done!"; }).onComplete(onSuccess(res -> { assertEquals("done!", res); testComplete(); @@ -41,12 +43,12 @@ public void testExecuteBlockingSuccess() { @Test public void testExecuteBlockingFailed() { - vertx.executeBlocking(future -> { + vertx.executeBlocking(() -> { try { Thread.sleep(1000); } catch (Exception ignore) { } - future.fail("failed!"); + throw new NoStackTraceException("failed!"); }).onComplete(onFailure(t -> { assertEquals("failed!", t.getMessage()); testComplete(); @@ -57,7 +59,7 @@ public void testExecuteBlockingFailed() { @Test public void testExecuteBlockingThrowsRTE() { - vertx.executeBlocking(future -> { + vertx.executeBlocking(() -> { throw new RuntimeException("rte"); }).onComplete(onFailure(t -> { assertEquals("rte", t.getMessage()); @@ -72,7 +74,7 @@ public void testExecuteBlockingContext() { vertx.runOnContext(v -> { Context ctx = vertx.getOrCreateContext(); assertTrue(ctx.isEventLoopContext()); - vertx.executeBlocking(future -> { + vertx.executeBlocking(() -> { assertSame(ctx, vertx.getOrCreateContext()); assertTrue(Thread.currentThread().getName().startsWith("vert.x-worker-thread")); assertTrue(Context.isOnWorkerThread()); @@ -81,13 +83,16 @@ public void testExecuteBlockingContext() { Thread.sleep(1000); } catch (Exception ignore) { } + CountDownLatch latch = new CountDownLatch(1); vertx.runOnContext(v2 -> { assertSame(ctx, vertx.getOrCreateContext()); assertTrue(Thread.currentThread().getName().startsWith("vert.x-eventloop-thread")); assertFalse(Context.isOnWorkerThread()); assertTrue(Context.isOnEventLoopThread()); - future.complete("done!"); + latch.countDown(); }); + assertTrue(latch.await(20, TimeUnit.SECONDS)); + return "done!"; }).onComplete(onSuccess(res -> { assertSame(ctx, vertx.getOrCreateContext()); assertTrue(Thread.currentThread().getName().startsWith("vert.x-eventloop-thread")); @@ -107,9 +112,9 @@ public void testExecuteBlockingTTCL() throws Exception { assertNotNull(cl); CountDownLatch latch = new CountDownLatch(1); AtomicReference blockingTCCL = new AtomicReference<>(); - vertx.executeBlocking(future -> { - future.complete("whatever"); + vertx.executeBlocking(() -> { blockingTCCL.set(Thread.currentThread().getContextClassLoader()); + return "whatever"; }).onComplete(onSuccess(res -> { assertEquals("whatever", res); latch.countDown(); @@ -132,7 +137,7 @@ public void testExecuteBlockingParallel() throws Exception { assertTrue(ctx.isEventLoopContext()); for (int i = 0; i < numExecBlocking; i++) { - vertx.executeBlocking(future -> { + vertx.executeBlocking(() -> { assertSame(ctx, vertx.getOrCreateContext()); assertTrue(Thread.currentThread().getName().startsWith("vert.x-worker-thread")); assertTrue(Context.isOnWorkerThread()); @@ -141,7 +146,7 @@ public void testExecuteBlockingParallel() throws Exception { Thread.sleep(pause); } catch (Exception ignore) { } - future.complete("done!"); + return "done!"; }, false).onComplete(onSuccess(res -> { assertSame(ctx, vertx.getOrCreateContext()); assertTrue(Thread.currentThread().getName().startsWith("vert.x-eventloop-thread")); diff --git a/src/test/java/io/vertx/core/FakeContext.java b/src/test/java/io/vertx/core/FakeContext.java index e5ed6edc209..240781d69b6 100644 --- a/src/test/java/io/vertx/core/FakeContext.java +++ b/src/test/java/io/vertx/core/FakeContext.java @@ -43,11 +43,6 @@ public boolean inThread() { return false; } - @Override - public Future<@Nullable T> executeBlocking(Handler> blockingCodeHandler, boolean ordered) { - return null; - } - @Override public Future<@Nullable T> executeBlocking(Callable blockingCodeHandler, boolean ordered) { return null; @@ -93,31 +88,16 @@ public EventLoop nettyEventLoop() { return null; } - @Override - public Future executeBlocking(Handler> blockingCodeHandler, TaskQueue queue) { - return null; - } - @Override public Future executeBlocking(Callable blockingCodeHandler, TaskQueue queue) { return null; } - @Override - public Future executeBlockingInternal(Handler> action) { - return null; - } - @Override public Future executeBlockingInternal(Callable action) { return null; } - @Override - public Future executeBlockingInternal(Handler> action, boolean ordered) { - return null; - } - @Override public Future executeBlockingInternal(Callable action, boolean ordered) { return null; diff --git a/src/test/java/io/vertx/core/HATest.java b/src/test/java/io/vertx/core/HATest.java index 9fb700215ca..9e01693fd09 100644 --- a/src/test/java/io/vertx/core/HATest.java +++ b/src/test/java/io/vertx/core/HATest.java @@ -397,13 +397,9 @@ protected void checkDeploymentExists(int pos, String verticleName, DeploymentOpt protected void kill(int pos) { VertxInternal v = (VertxInternal)vertices[pos]; - v.executeBlocking(fut -> { - try { - v.simulateKill(); - fut.complete(); - } catch (Exception e) { - fut.fail(e); - } + v.executeBlocking(() -> { + v.simulateKill(); + return null; }, false).onComplete(onSuccess(ar -> { })); } diff --git a/src/test/java/io/vertx/core/NamedWorkerPoolTest.java b/src/test/java/io/vertx/core/NamedWorkerPoolTest.java index 6603e3e2653..4b3cea7c8af 100644 --- a/src/test/java/io/vertx/core/NamedWorkerPoolTest.java +++ b/src/test/java/io/vertx/core/NamedWorkerPoolTest.java @@ -39,12 +39,12 @@ public void testThread() { AtomicBoolean onWorkerThread = new AtomicBoolean(); AtomicBoolean onEventLoopThread = new AtomicBoolean(); AtomicReference threadName = new AtomicReference<>(); - worker.executeBlocking(fut -> { + worker.executeBlocking(() -> { onVertxThread.set(Context.isOnVertxThread()); onWorkerThread.set(Context.isOnWorkerThread()); onEventLoopThread.set(Context.isOnEventLoopThread()); threadName.set(Thread.currentThread().getName()); - fut.complete(null); + return null; }).onComplete(ar -> { testComplete(); }); @@ -69,13 +69,13 @@ public void testOrdered() { for (int i = 0;i < num;i++) { boolean first = i == 0; boolean last = i == num - 1; - worker.executeBlocking(fut -> { + worker.executeBlocking(() -> { if (first) { try { awaitLatch(submitted); } catch (InterruptedException e) { fail(e); - return; + return null; } assertNull(t.get()); t.set(Thread.currentThread()); @@ -83,7 +83,7 @@ public void testOrdered() { assertEquals(t.get(), Thread.currentThread()); } assertTrue(Thread.currentThread().getName().startsWith(poolName + "-")); - fut.complete(null); + return null; }).onComplete(ar -> { if (last) { testComplete(); @@ -106,16 +106,16 @@ public void testUnordered() throws Exception { Context ctx = vertx.getOrCreateContext(); ctx.runOnContext(v -> { for (int i = 0; i < num; i++) { - worker.executeBlocking(fut -> { + worker.executeBlocking(() -> { latch1.countDown(); try { awaitLatch(latch2); } catch (InterruptedException e) { fail(e); - return; + return null; } assertTrue(Thread.currentThread().getName().startsWith(poolName + "-")); - fut.complete(null); + return null; }, false).onComplete(ar -> { complete(); }); @@ -138,7 +138,7 @@ public void start() throws Exception { AtomicReference currentThread = new AtomicReference<>(); for (int i = 0;i < count;i++) { int val = i; - exec.executeBlocking(fut -> { + exec.executeBlocking(() -> { Thread current = Thread.currentThread(); assertNotSame(startThread, current); if (val == 0) { @@ -146,7 +146,7 @@ public void start() throws Exception { } else { assertSame(current, currentThread.get()); } - fut.complete(); + return null; }, true).onComplete(onSuccess(v -> complete())); } } @@ -163,9 +163,10 @@ public void testPoolSize() throws Exception { CountDownLatch latch1 = new CountDownLatch(poolSize * 100); Set names = Collections.synchronizedSet(new HashSet<>()); for (int i = 0;i < poolSize * 100;i++) { - worker.executeBlocking(fut -> { + worker.executeBlocking(() -> { names.add(Thread.currentThread().getName()); latch1.countDown(); + return null; }, false); } awaitLatch(latch1); @@ -210,13 +211,13 @@ public void testMaxExecuteTime3() { } public void testMaxExecuteTime(WorkerExecutor worker, long maxExecuteTime, TimeUnit maxExecuteTimeUnit) { - worker.executeBlocking(f -> { + worker.executeBlocking(() -> { Thread t = Thread.currentThread(); assertTrue(t instanceof VertxThread); VertxThread thread = (VertxThread) t; assertEquals(maxExecuteTime, thread.maxExecTime()); assertEquals(maxExecuteTimeUnit, thread.maxExecTimeUnit()); - f.complete(); + return null; }).onComplete(res -> { testComplete(); }); @@ -229,8 +230,9 @@ public void testCloseWorkerPool() throws Exception { AtomicReference thread = new AtomicReference<>(); WorkerExecutor worker1 = vertx.createSharedWorkerExecutor(poolName); WorkerExecutor worker2 = vertx.createSharedWorkerExecutor(poolName); - worker1.executeBlocking(fut -> { + worker1.executeBlocking(() -> { thread.set(Thread.currentThread()); + return null; }); assertWaitUntil(() -> thread.get() != null); worker1.close(); @@ -253,7 +255,10 @@ public void start() throws Exception { String deploymentId = deploymentIdRef.get(20, SECONDS); vertx.undeploy(deploymentId).onComplete(onSuccess(v -> { try { - pool.get().executeBlocking(fut -> fail()); + pool.get().executeBlocking(() -> { + fail(); + return null; + }); fail(); } catch (RejectedExecutionException ignore) { testComplete(); @@ -271,13 +276,13 @@ public void testDeployUsingNamedPool() throws Exception { @Override public void start() { vertx.runOnContext(v1 -> { - vertx.executeBlocking(fut -> { + vertx.executeBlocking(() -> { thread.set(Thread.currentThread()); assertTrue(Context.isOnVertxThread()); assertTrue(Context.isOnWorkerThread()); assertFalse(Context.isOnEventLoopThread()); assertTrue(Thread.currentThread().getName().startsWith(poolName + "-")); - fut.complete(); + return null; }).onComplete(onSuccess(v2 -> { vertx.undeploy(context.deploymentID()).onComplete(undeployed); })); @@ -333,12 +338,18 @@ public void testCloseWorkerPoolsWhenVertxCloses() { WorkerExecutor exec = vertx.createSharedWorkerExecutor("vert.x-123"); vertx.close().onComplete(v -> { try { - vertx.executeBlocking(fut -> fail()).onComplete(ar -> fail()); + vertx.executeBlocking(() -> { + fail(); + return null; + }).onComplete(ar -> fail()); fail(); } catch (RejectedExecutionException ignore) { } try { - exec.executeBlocking(fut -> fail()).onComplete(ar -> fail()); + exec.executeBlocking(() -> { + fail(); + return null; + }).onComplete(ar -> fail()); fail(); } catch (RejectedExecutionException ignore) { } @@ -356,7 +367,7 @@ public void testReuseWorkerPoolNameAfterVerticleIsUndeployed() throws Exception vertx.deployVerticle(new AbstractVerticle() { @Override public void start(Promise startPromise) { - vertx.executeBlocking(Promise::complete).onComplete(startPromise); + vertx.executeBlocking(() -> null).onComplete(startPromise); } }, new DeploymentOptions().setWorkerPoolName("foo")).onComplete(onSuccess(id -> { ref.set(id); @@ -372,7 +383,7 @@ public void start(Promise startPromise) { vertx.deployVerticle(new AbstractVerticle() { @Override public void start(Promise startPromise) { - vertx.executeBlocking(Promise::complete).onComplete(startPromise); + vertx.executeBlocking(() -> null).onComplete(startPromise); } }, new DeploymentOptions().setWorkerPoolName("foo")).onComplete(onSuccess(id -> { deployLatch2.countDown(); diff --git a/src/test/java/io/vertx/core/VertxTest.java b/src/test/java/io/vertx/core/VertxTest.java index 83a50a4a383..1e757bd4053 100644 --- a/src/test/java/io/vertx/core/VertxTest.java +++ b/src/test/java/io/vertx/core/VertxTest.java @@ -380,13 +380,13 @@ public void testFinalizeSharedWorkerExecutor() throws Exception { VertxInternal vertx = (VertxInternal) Vertx.vertx(); try { Thread[] threads = new Thread[2]; - vertx.createSharedWorkerExecutor("LeakTest").executeBlocking(promise -> { + vertx.createSharedWorkerExecutor("LeakTest").executeBlocking(() -> { threads[0] = Thread.currentThread(); - promise.complete(); + return null; }).toCompletionStage().toCompletableFuture().get(20, TimeUnit.SECONDS); - vertx.createSharedWorkerExecutor("LeakTest").executeBlocking(promise -> { + vertx.createSharedWorkerExecutor("LeakTest").executeBlocking(() -> { threads[1] = Thread.currentThread(); - promise.complete(); + return null; }).toCompletionStage().toCompletableFuture().get(20, TimeUnit.SECONDS); runGC(); assertFalse(threads[0].isAlive()); @@ -501,8 +501,8 @@ public void testThreadLeak() throws Exception { Vertx vertx = Vertx.vertx(); try { WorkerExecutor exec = vertx.createSharedWorkerExecutor("pool"); - WeakReference ref = exec.>executeBlocking(p -> { - p.complete(new WeakReference<>(Thread.currentThread())); + WeakReference ref = exec.executeBlocking(() -> { + return new WeakReference<>(Thread.currentThread()); }).toCompletionStage().toCompletableFuture().get(); exec.close().toCompletionStage().toCompletableFuture().get(); long now = System.currentTimeMillis(); diff --git a/src/test/java/io/vertx/core/eventbus/EventBusTestBase.java b/src/test/java/io/vertx/core/eventbus/EventBusTestBase.java index f06eea8e7c3..7ef73b88356 100644 --- a/src/test/java/io/vertx/core/eventbus/EventBusTestBase.java +++ b/src/test/java/io/vertx/core/eventbus/EventBusTestBase.java @@ -488,15 +488,15 @@ public void testSendFromExecuteBlocking() throws Exception { receivedLatch.countDown(); }).completion().onComplete(ar -> { assertTrue(ar.succeeded()); - vertices[0].executeBlocking(fut -> { + vertices[0].executeBlocking(() -> { vertices[0].eventBus().send(ADDRESS1, expectedBody); try { awaitLatch(receivedLatch); // Make sure message is sent even if we're busy } catch (InterruptedException e) { Thread.interrupted(); - fut.fail(e); + throw e; } - fut.complete(); + return null; }).onComplete(onSuccess(ar2 -> testComplete())); }); await(); @@ -553,7 +553,7 @@ public void start() throws Exception { }, new DeploymentOptions().setWorker(true)); // Inside executeBlocking - vertices[0].executeBlocking(fut -> { + vertices[0].executeBlocking(() -> { vertices[0].eventBus().request("blah", "blah").onComplete(onFailure(err -> { if (err instanceof ReplyException) { ReplyException cause = (ReplyException) err; @@ -564,7 +564,7 @@ public void start() throws Exception { assertTrue("Not an EL thread", Context.isOnEventLoopThread()); complete(); })); - fut.complete(); + return null; }, false); await(); diff --git a/src/test/java/io/vertx/core/eventbus/MessageQueueOnWorkerThreadTest.java b/src/test/java/io/vertx/core/eventbus/MessageQueueOnWorkerThreadTest.java index 28ff053e0e6..2cc6bb01db2 100644 --- a/src/test/java/io/vertx/core/eventbus/MessageQueueOnWorkerThreadTest.java +++ b/src/test/java/io/vertx/core/eventbus/MessageQueueOnWorkerThreadTest.java @@ -112,7 +112,7 @@ public void registrationsLost() { } } - private static class SenderVerticle extends AbstractVerticle { + private class SenderVerticle extends AbstractVerticle { final boolean worker; int count; @@ -123,19 +123,25 @@ private static class SenderVerticle extends AbstractVerticle { } @Override - public void start() throws Exception { + public void start() { sendMessage(); } void sendMessage() { if (worker) { - vertx.executeBlocking(prom -> { + vertx.executeBlocking(() -> { if (count > 0) { vertx.eventBus().send("foo", "bar"); count--; - prom.complete(); + return true; + } else { + return false; } - }).onComplete(ar -> vertx.runOnContext(v -> sendMessage())); + }).onComplete(onSuccess(cont -> { + if (cont) { + vertx.runOnContext(v -> sendMessage()); + } + })); } else { if (count > 0) { vertx.eventBus().send("foo", "bar"); diff --git a/src/test/java/io/vertx/core/file/FileSystemTest.java b/src/test/java/io/vertx/core/file/FileSystemTest.java index a6dd3a17713..1a5402fdfad 100644 --- a/src/test/java/io/vertx/core/file/FileSystemTest.java +++ b/src/test/java/io/vertx/core/file/FileSystemTest.java @@ -1988,13 +1988,7 @@ public void testCopyFileAttributes() throws Exception { assertEquals(expected.creationTime(), actual.creationTime()); assertEquals(expected.lastModifiedTime(), actual.lastModifiedTime()); })) - .compose(v2 -> vertx.>executeBlocking(fut -> { - try { - fut.complete(Files.getPosixFilePermissions(new File(testDir, target).toPath(), LinkOption.NOFOLLOW_LINKS)); - } catch (IOException e) { - fut.fail(e); - } - })))).onComplete(onSuccess(perms -> { + .compose(v2 -> vertx.executeBlocking(() -> Files.getPosixFilePermissions(new File(testDir, target).toPath(), LinkOption.NOFOLLOW_LINKS))))).onComplete(onSuccess(perms -> { assertEquals(EnumSet.of(PosixFilePermission.OWNER_READ), perms); complete(); })); diff --git a/src/test/java/io/vertx/core/shareddata/AsynchronousLockTest.java b/src/test/java/io/vertx/core/shareddata/AsynchronousLockTest.java index 415c31ae3a6..28874d4d1b6 100644 --- a/src/test/java/io/vertx/core/shareddata/AsynchronousLockTest.java +++ b/src/test/java/io/vertx/core/shareddata/AsynchronousLockTest.java @@ -12,6 +12,7 @@ package io.vertx.core.shareddata; import io.vertx.core.*; +import io.vertx.core.impl.NoStackTraceException; import io.vertx.core.shareddata.impl.LockInternal; import io.vertx.test.core.VertxTestBase; import org.junit.Test; @@ -124,7 +125,7 @@ public void testAcquireOnExecuteBlocking() { SharedData sharedData = vertx.sharedData(); AtomicReference start = new AtomicReference<>(); - vertx.executeBlocking(future -> { + vertx.executeBlocking(() -> { CountDownLatch acquireLatch = new CountDownLatch(1); AtomicReference> lockReference = new AtomicReference<>(); sharedData @@ -137,19 +138,19 @@ public void testAcquireOnExecuteBlocking() { awaitLatch(acquireLatch); AsyncResult ar = lockReference.get(); if (ar.succeeded()) { - future.complete(ar.result()); + return ar.result(); } else { - future.fail(ar.cause()); + throw new NoStackTraceException(ar.cause()); } } catch (InterruptedException e) { - future.fail(e); + throw e; } }).compose(lock -> { start.set(System.currentTimeMillis()); vertx.setTimer(1000, tid -> { lock.release(); }); - return vertx.executeBlocking(future -> { + return vertx.executeBlocking(() -> { CountDownLatch acquireLatch = new CountDownLatch(1); AtomicReference> lockReference = new AtomicReference<>(); sharedData @@ -162,12 +163,12 @@ public void testAcquireOnExecuteBlocking() { awaitLatch(acquireLatch); AsyncResult ar3 = lockReference.get(); if (ar3.succeeded()) { - future.complete(ar3.result()); + return ar3.result(); } else { - future.fail(ar3.cause()); + throw new NoStackTraceException(ar3.cause()); } } catch (InterruptedException e) { - future.fail(e); + throw e; } }); }).onComplete(onSuccess(v -> { diff --git a/src/test/java/io/vertx/core/spi/metrics/MetricsTest.java b/src/test/java/io/vertx/core/spi/metrics/MetricsTest.java index 43c3bd7401a..0fe75a53df9 100644 --- a/src/test/java/io/vertx/core/spi/metrics/MetricsTest.java +++ b/src/test/java/io/vertx/core/spi/metrics/MetricsTest.java @@ -36,6 +36,7 @@ import org.junit.Test; import java.util.*; +import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -912,14 +913,13 @@ public void testThreadPoolMetricsWithExecuteBlocking() throws Exception { assertThat(metrics.getPoolSize(), is(getOptions().getInternalBlockingPoolSize())); assertThat(metrics.numberOfIdleThreads(), is(getOptions().getWorkerPoolSize())); - Handler> job = getSomeDumbTask(); + Callable job = getSomeDumbTask(); AtomicBoolean hadWaitingQueue = new AtomicBoolean(); AtomicBoolean hadIdle = new AtomicBoolean(); AtomicBoolean hadRunning = new AtomicBoolean(); for (int i = 0; i < 100; i++) { - vertx.executeBlocking( - job).onComplete( + vertx.executeBlocking(job).onComplete( ar -> { if (metrics.numberOfWaitingTasks() > 0) { hadWaitingQueue.set(true); @@ -964,7 +964,7 @@ public void testThreadPoolMetricsWithInternalExecuteBlocking() { Map latches = new HashMap<>(); for (int i = 0; i < count; i++) { CountDownLatch latch = latches.computeIfAbsent(i / num, k -> new CountDownLatch(num)); - v.executeBlockingInternal(fut -> { + v.executeBlockingInternal(() -> { latch.countDown(); try { awaitLatch(latch); @@ -978,7 +978,7 @@ public void testThreadPoolMetricsWithInternalExecuteBlocking() { if (metrics.numberOfWaitingTasks() > 0) { hadWaitingQueue.set(true); } - fut.complete(); + return null; }, false).onComplete(ar -> { if (metrics.numberOfIdleThreads() > 0) { hadIdle.set(true); @@ -1080,7 +1080,7 @@ public void testThreadPoolMetricsWithNamedExecuteBlocking() throws InterruptedEx assertThat(metrics.getPoolSize(), is(10)); assertThat(metrics.numberOfIdleThreads(), is(10)); - Handler> job = getSomeDumbTask(); + Callable job = getSomeDumbTask(); AtomicBoolean hadWaitingQueue = new AtomicBoolean(); AtomicBoolean hadIdle = new AtomicBoolean(); @@ -1135,14 +1135,14 @@ public void testWorkerPoolClose() { assertTrue(metrics2.isClosed()); } - private Handler> getSomeDumbTask() { - return (future) -> { + private Callable getSomeDumbTask() { + return () -> { try { Thread.sleep(50); } catch (InterruptedException e) { Thread.currentThread().isInterrupted(); } - future.complete(null); + return null; }; } diff --git a/src/test/java/io/vertx/core/spi/tracing/TracerTest.java b/src/test/java/io/vertx/core/spi/tracing/TracerTest.java index d9ef7344f2d..43814e633ce 100644 --- a/src/test/java/io/vertx/core/spi/tracing/TracerTest.java +++ b/src/test/java/io/vertx/core/spi/tracing/TracerTest.java @@ -43,7 +43,7 @@ public void testWorkerExecutor() { ContextInternal ctx = (ContextInternal) vertx.getOrCreateContext(); ContextInternal duplicate = ctx.duplicate(); duplicate.runOnContext(v -> { - exec.executeBlocking(Promise::complete).onComplete(onSuccess(res -> { + exec.executeBlocking(() -> null).onComplete(onSuccess(res -> { testComplete(); })); }); diff --git a/src/test/java/io/vertx/it/ExecutorServiceFactoryTest.java b/src/test/java/io/vertx/it/ExecutorServiceFactoryTest.java index 6dc1cab1081..4a5ea7b3cb9 100644 --- a/src/test/java/io/vertx/it/ExecutorServiceFactoryTest.java +++ b/src/test/java/io/vertx/it/ExecutorServiceFactoryTest.java @@ -32,9 +32,9 @@ public void testExecuteBlocking() throws Exception { int num = 10; CountDownLatch latch = new CountDownLatch(num); for (int i = 0;i < num;i++) { - vertx.executeBlocking(p -> { + vertx.executeBlocking(() -> { assertTrue(CustomExecutorService.executing.get()); - p.complete(); + return null; }).onComplete(onSuccess(v -> { latch.countDown(); })); diff --git a/src/test/java/io/vertx/test/fakecluster/FakeClusterManager.java b/src/test/java/io/vertx/test/fakecluster/FakeClusterManager.java index dfe394c8c83..194ae22f896 100644 --- a/src/test/java/io/vertx/test/fakecluster/FakeClusterManager.java +++ b/src/test/java/io/vertx/test/fakecluster/FakeClusterManager.java @@ -176,12 +176,12 @@ public void getNodeInfo(String nodeId, Promise promise) { @Override public void join(Promise promise) { - vertx.executeBlocking(fut -> { + vertx.executeBlocking(() -> { synchronized (this) { this.nodeID = UUID.randomUUID().toString(); doJoin(nodeID, this); } - fut.complete(); + return null; }).onComplete(promise); } @@ -198,7 +198,7 @@ public void leave(Promise promise) { events.add(new RegistrationUpdateEvent(address, current)); }); fireRegistrationUpdateEvents(events, true); - vertx.executeBlocking(fut -> { + vertx.executeBlocking(() -> { synchronized (this) { if (nodeID != null) { nodeInfos.remove(nodeID); @@ -209,7 +209,7 @@ public void leave(Promise promise) { this.nodeID = null; } } - fut.complete(); + return null; }).onComplete(promise); } From 26631200ea145627552b39ba798437e8b1eecaf8 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Mon, 17 Jul 2023 09:36:02 +0200 Subject: [PATCH 025/264] Remove useless code --- src/main/java/io/vertx/core/impl/ContextBase.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/main/java/io/vertx/core/impl/ContextBase.java b/src/main/java/io/vertx/core/impl/ContextBase.java index 349db5c9aef..9e3fe006cbe 100644 --- a/src/main/java/io/vertx/core/impl/ContextBase.java +++ b/src/main/java/io/vertx/core/impl/ContextBase.java @@ -145,17 +145,6 @@ static Future executeBlocking(ContextInternal context, Callable blocki }, workerPool, queue); } - static Future executeBlocking(ContextInternal context, Handler> blockingCodeHandler, - WorkerPool workerPool, TaskQueue queue) { - return internalExecuteBlocking(context, promise -> { - try { - blockingCodeHandler.handle(promise); - } catch (Throwable e) { - promise.tryFail(e); - } - }, workerPool, queue); - } - private static Future internalExecuteBlocking(ContextInternal context, Handler> blockingCodeHandler, WorkerPool workerPool, TaskQueue queue) { PoolMetrics metrics = workerPool.metrics(); From a13997087c26a64a6a216275849f5d11e79065f3 Mon Sep 17 00:00:00 2001 From: Eddie Pyne Date: Thu, 20 Jul 2023 15:15:53 -0400 Subject: [PATCH 026/264] Fix SSLOptions equals method to use sslHandshakeTimeout from argument --- src/main/java/io/vertx/core/net/SSLOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/vertx/core/net/SSLOptions.java b/src/main/java/io/vertx/core/net/SSLOptions.java index 826519d19f7..de30d5d1f3a 100644 --- a/src/main/java/io/vertx/core/net/SSLOptions.java +++ b/src/main/java/io/vertx/core/net/SSLOptions.java @@ -331,7 +331,7 @@ public boolean equals(Object obj) { } if (obj instanceof SSLOptions) { SSLOptions that = (SSLOptions) obj; - return sslHandshakeTimeoutUnit.toNanos(sslHandshakeTimeout) == that.sslHandshakeTimeoutUnit.toNanos(sslHandshakeTimeout) && + return sslHandshakeTimeoutUnit.toNanos(sslHandshakeTimeout) == that.sslHandshakeTimeoutUnit.toNanos(that.sslHandshakeTimeout) && Objects.equals(keyCertOptions, that.keyCertOptions) && Objects.equals(trustOptions, that.trustOptions) && Objects.equals(enabledCipherSuites, that.enabledCipherSuites) && From c5b29b1b75a2859bd72ea09782c46f2e6f9be875 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Tue, 25 Jul 2023 16:32:04 +0200 Subject: [PATCH 027/264] Added a test for server sharing updating a SSL options on all servers --- .../java/io/vertx/core/http/HttpTLSTest.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/test/java/io/vertx/core/http/HttpTLSTest.java b/src/test/java/io/vertx/core/http/HttpTLSTest.java index f259b11ba48..794f38b50db 100755 --- a/src/test/java/io/vertx/core/http/HttpTLSTest.java +++ b/src/test/java/io/vertx/core/http/HttpTLSTest.java @@ -1741,6 +1741,34 @@ public void testConcurrentUpdateSSLOptions() throws Exception { await(); } + @Test + public void testServerSharingUpdateSSLOptions() throws Exception { + int numServers = 4; + HttpServer[] servers = new HttpServer[numServers]; + for (int i = 0;i < numServers;i++) { + String msg = "Hello World " + i; + servers[i] = createHttpServer(createBaseServerOptions().setSsl(true).setKeyCertOptions(Cert.SERVER_JKS.get())) + .requestHandler(req -> { + req.response().end(msg); + }); + awaitFuture(servers[i].listen(testAddress)); + } + client = createHttpClient(new HttpClientOptions().setKeepAlive(false).setSsl(true).setTrustOptions(Trust.SERVER_JKS.get())); + for (int i = 0;i < numServers;i++) { + Buffer body = awaitFuture(client.request(requestOptions).compose(req -> req.send().compose(HttpClientResponse::body))); + assertEquals("Hello World " + i, body.toString()); + } + client.close(); + for (int i = 0;i < numServers;i++) { + awaitFuture(servers[i].updateSSLOptions(new SSLOptions().setKeyCertOptions(Cert.SERVER_PKCS12.get()))); + } + client = createHttpClient(new HttpClientOptions().setKeepAlive(false).setSsl(true).setTrustOptions(Trust.SERVER_PKCS12.get())); + for (int i = 0;i < numServers;i++) { + Buffer body = awaitFuture(client.request(requestOptions).compose(req -> req.send().compose(HttpClientResponse::body))); + assertEquals("Hello World " + i, body.toString()); + } + } + @Test public void testEngineUseEventLoopThread() throws Exception { testUseThreadPool(false, false); From a4d85b9ee33d41a21ec5d0f268b4fa12242d3bc0 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Wed, 26 Jul 2023 09:20:34 +0200 Subject: [PATCH 028/264] Remove Netty specific API from Vert.x public API --- src/main/java/io/vertx/core/Vertx.java | 8 - .../java/io/vertx/core/buffer/Buffer.java | 45 +--- .../io/vertx/core/buffer/impl/BufferImpl.java | 124 +++++------ .../core/buffer/impl/BufferInternal.java | 203 ++++++++++++++++++ .../datagram/impl/DatagramSocketImpl.java | 5 +- .../vertx/core/file/impl/AsyncFileImpl.java | 4 +- .../http/impl/Http1xClientConnection.java | 3 +- .../http/impl/Http1xServerConnection.java | 3 +- .../core/http/impl/Http1xServerRequest.java | 5 +- .../core/http/impl/Http1xServerResponse.java | 11 +- .../core/http/impl/Http2ConnectionBase.java | 7 +- .../core/http/impl/Http2ServerRequest.java | 3 +- .../core/http/impl/Http2ServerResponse.java | 11 +- .../core/http/impl/HttpClientRequestImpl.java | 15 +- .../core/http/impl/HttpClientStream.java | 5 +- .../vertx/core/http/impl/NettyFileUpload.java | 5 +- .../impl/VertxHttp2ConnectionHandler.java | 5 +- .../WebSocketHandshakeInboundHandler.java | 3 +- .../core/http/impl/WebSocketImplBase.java | 9 +- .../core/http/impl/ws/WebSocketFrameImpl.java | 11 +- .../io/vertx/core/impl/VertxInternal.java | 7 + .../core/json/jackson/DatabindCodec.java | 3 +- .../vertx/core/json/jackson/JacksonCodec.java | 5 +- .../io/vertx/core/net/impl/NetSocketImpl.java | 5 +- .../parsetools/impl/RecordParserImpl.java | 3 +- .../io/vertx/core/EventLoopGroupTest.java | 28 --- .../java/io/vertx/core/buffer/BufferTest.java | 27 +-- .../io/vertx/core/datagram/DatagramTest.java | 3 +- .../core/dns/HostnameResolutionTest.java | 2 +- .../io/vertx/core/file/FileSystemTest.java | 3 +- .../io/vertx/core/http/Http2ClientTest.java | 7 +- .../io/vertx/core/http/Http2ServerTest.java | 35 +-- .../core/http/HttpBandwidthLimitingTest.java | 2 +- .../core/http/HttpCompressionTestBase.java | 3 +- .../io/vertx/core/http/WebSocketTest.java | 29 +-- src/test/java/io/vertx/core/net/NetTest.java | 5 +- .../vertx/core/spi/metrics/MetricsTest.java | 2 +- .../java/io/vertx/test/core/TestUtils.java | 5 +- 38 files changed, 403 insertions(+), 256 deletions(-) create mode 100644 src/main/java/io/vertx/core/buffer/impl/BufferInternal.java delete mode 100644 src/test/java/io/vertx/core/EventLoopGroupTest.java diff --git a/src/main/java/io/vertx/core/Vertx.java b/src/main/java/io/vertx/core/Vertx.java index 52b807003b8..1082c0028f6 100644 --- a/src/main/java/io/vertx/core/Vertx.java +++ b/src/main/java/io/vertx/core/Vertx.java @@ -482,14 +482,6 @@ default Future deployVerticle(String name) { return executeBlocking(blockingCodeHandler, true); } - /** - * Return the Netty EventLoopGroup used by Vert.x - * - * @return the EventLoopGroup - */ - @GenIgnore(GenIgnore.PERMITTED_TYPE) - EventLoopGroup nettyEventLoopGroup(); - /** * Like {@link #createSharedWorkerExecutor(String, int)} but with the {@link VertxOptions#setWorkerPoolSize} {@code poolSize}. */ diff --git a/src/main/java/io/vertx/core/buffer/Buffer.java b/src/main/java/io/vertx/core/buffer/Buffer.java index 1b919d96809..727382bfff8 100644 --- a/src/main/java/io/vertx/core/buffer/Buffer.java +++ b/src/main/java/io/vertx/core/buffer/Buffer.java @@ -12,11 +12,10 @@ package io.vertx.core.buffer; -import io.netty.buffer.ByteBuf; import io.vertx.codegen.annotations.Fluent; import io.vertx.codegen.annotations.GenIgnore; import io.vertx.codegen.annotations.VertxGen; -import io.vertx.core.buffer.impl.BufferImpl; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.json.Json; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; @@ -25,7 +24,6 @@ import java.nio.ByteBuffer; import java.nio.charset.Charset; -import java.util.Objects; /** * Most data is shuffled around inside Vert.x using buffers. @@ -46,7 +44,7 @@ public interface Buffer extends ClusterSerializable, Shareable { * @return the buffer */ static Buffer buffer() { - return BufferImpl.buffer(); + return BufferInternal.buffer(); } /** @@ -59,7 +57,7 @@ static Buffer buffer() { * @return the buffer */ static Buffer buffer(int initialSizeHint) { - return BufferImpl.buffer(initialSizeHint); + return BufferInternal.buffer(initialSizeHint); } /** @@ -69,7 +67,7 @@ static Buffer buffer(int initialSizeHint) { * @return the buffer */ static Buffer buffer(String string) { - return BufferImpl.buffer(string); + return BufferInternal.buffer(string); } /** @@ -80,7 +78,7 @@ static Buffer buffer(String string) { * @return the buffer */ static Buffer buffer(String string, String enc) { - return BufferImpl.buffer(string, enc); + return BufferInternal.buffer(string, enc); } /** @@ -91,30 +89,7 @@ static Buffer buffer(String string, String enc) { */ @GenIgnore(GenIgnore.PERMITTED_TYPE) static Buffer buffer(byte[] bytes) { - return BufferImpl.buffer(bytes); - } - - /** - *

- * Create a new buffer from a Netty {@code ByteBuf}. - * Note that the returned buffer is backed by given Netty ByteBuf, - * so changes in the returned buffer are reflected in given Netty ByteBuf, and vice-versa. - *

- *

- * For example, both buffers in the code below share their data: - *

- *
-   *   Buffer src = Buffer.buffer();
-   *   Buffer clone = Buffer.buffer(src.getByteBuf());
-   * 
- * - * @param byteBuf the Netty ByteBuf - * @return the buffer - */ - @GenIgnore(GenIgnore.PERMITTED_TYPE) - static Buffer buffer(ByteBuf byteBuf) { - Objects.requireNonNull(byteBuf); - return BufferImpl.buffer(byteBuf); + return BufferInternal.buffer(bytes); } /** @@ -701,12 +676,4 @@ default Object toJson() { */ Buffer slice(int start, int end); - /** - * Returns the Buffer as a Netty {@code ByteBuf}. - * - *

The returned buffer is a duplicate that maintain its own indices. - */ - @GenIgnore(GenIgnore.PERMITTED_TYPE) - ByteBuf getByteBuf(); - } diff --git a/src/main/java/io/vertx/core/buffer/impl/BufferImpl.java b/src/main/java/io/vertx/core/buffer/impl/BufferImpl.java index 38af5a8f0cd..f6766441b10 100644 --- a/src/main/java/io/vertx/core/buffer/impl/BufferImpl.java +++ b/src/main/java/io/vertx/core/buffer/impl/BufferImpl.java @@ -36,31 +36,7 @@ * * @author Tim Fox */ -public class BufferImpl implements Buffer { - - public static Buffer buffer(int initialSizeHint) { - return new BufferImpl(initialSizeHint); - } - - public static Buffer buffer() { - return new BufferImpl(); - } - - public static Buffer buffer(String str) { - return new BufferImpl(str); - } - - public static Buffer buffer(String str, String enc) { - return new BufferImpl(str, enc); - } - - public static Buffer buffer(byte[] bytes) { - return new BufferImpl(bytes); - } - - public static Buffer buffer(ByteBuf byteBuffer) { - return new BufferImpl(byteBuffer); - } +public class BufferImpl implements BufferInternal { private ByteBuf buffer; @@ -262,14 +238,14 @@ public String getString(int start, int end) { return new String(bytes, StandardCharsets.UTF_8); } - public Buffer appendBuffer(Buffer buff) { + public BufferImpl appendBuffer(Buffer buff) { BufferImpl impl = (BufferImpl) buff; ByteBuf byteBuf = impl.buffer; buffer.writeBytes(impl.buffer, byteBuf.readerIndex(), impl.buffer.readableBytes()); return this; } - public Buffer appendBuffer(Buffer buff, int offset, int len) { + public BufferImpl appendBuffer(Buffer buff, int offset, int len) { BufferImpl impl = (BufferImpl) buff; ByteBuf byteBuf = impl.buffer; int from = byteBuf.readerIndex() + offset; @@ -277,201 +253,201 @@ public Buffer appendBuffer(Buffer buff, int offset, int len) { return this; } - public Buffer appendBytes(byte[] bytes) { + public BufferImpl appendBytes(byte[] bytes) { buffer.writeBytes(bytes); return this; } - public Buffer appendBytes(byte[] bytes, int offset, int len) { + public BufferImpl appendBytes(byte[] bytes, int offset, int len) { buffer.writeBytes(bytes, offset, len); return this; } - public Buffer appendByte(byte b) { + public BufferImpl appendByte(byte b) { buffer.writeByte(b); return this; } - public Buffer appendUnsignedByte(short b) { + public BufferImpl appendUnsignedByte(short b) { buffer.writeByte(b); return this; } - public Buffer appendInt(int i) { + public BufferImpl appendInt(int i) { buffer.writeInt(i); return this; } - public Buffer appendIntLE(int i) { + public BufferImpl appendIntLE(int i) { buffer.writeIntLE(i); return this; } - public Buffer appendUnsignedInt(long i) { + public BufferImpl appendUnsignedInt(long i) { buffer.writeInt((int) i); return this; } - public Buffer appendUnsignedIntLE(long i) { + public BufferImpl appendUnsignedIntLE(long i) { buffer.writeIntLE((int) i); return this; } - public Buffer appendMedium(int i) { + public BufferImpl appendMedium(int i) { buffer.writeMedium(i); return this; } - public Buffer appendMediumLE(int i) { + public BufferImpl appendMediumLE(int i) { buffer.writeMediumLE(i); return this; } - public Buffer appendLong(long l) { + public BufferImpl appendLong(long l) { buffer.writeLong(l); return this; } - public Buffer appendLongLE(long l) { + public BufferImpl appendLongLE(long l) { buffer.writeLongLE(l); return this; } - public Buffer appendShort(short s) { + public BufferImpl appendShort(short s) { buffer.writeShort(s); return this; } - public Buffer appendShortLE(short s) { + public BufferImpl appendShortLE(short s) { buffer.writeShortLE(s); return this; } - public Buffer appendUnsignedShort(int s) { + public BufferImpl appendUnsignedShort(int s) { buffer.writeShort(s); return this; } - public Buffer appendUnsignedShortLE(int s) { + public BufferImpl appendUnsignedShortLE(int s) { buffer.writeShortLE(s); return this; } - public Buffer appendFloat(float f) { + public BufferImpl appendFloat(float f) { buffer.writeFloat(f); return this; } - public Buffer appendDouble(double d) { + public BufferImpl appendDouble(double d) { buffer.writeDouble(d); return this; } - public Buffer appendString(String str, String enc) { + public BufferImpl appendString(String str, String enc) { return append(str, Charset.forName(Objects.requireNonNull(enc))); } - public Buffer appendString(String str) { + public BufferImpl appendString(String str) { return append(str, CharsetUtil.UTF_8); } - public Buffer setByte(int pos, byte b) { + public BufferImpl setByte(int pos, byte b) { ensureLength(pos + 1); buffer.setByte(pos, b); return this; } - public Buffer setUnsignedByte(int pos, short b) { + public BufferImpl setUnsignedByte(int pos, short b) { ensureLength(pos + 1); buffer.setByte(pos, b); return this; } - public Buffer setInt(int pos, int i) { + public BufferImpl setInt(int pos, int i) { ensureLength(pos + 4); buffer.setInt(pos, i); return this; } - public Buffer setIntLE(int pos, int i) { + public BufferImpl setIntLE(int pos, int i) { ensureLength(pos + 4); buffer.setIntLE(pos, i); return this; } - public Buffer setUnsignedInt(int pos, long i) { + public BufferImpl setUnsignedInt(int pos, long i) { ensureLength(pos + 4); buffer.setInt(pos, (int) i); return this; } - public Buffer setUnsignedIntLE(int pos, long i) { + public BufferImpl setUnsignedIntLE(int pos, long i) { ensureLength(pos + 4); buffer.setIntLE(pos, (int) i); return this; } - public Buffer setMedium(int pos, int i) { + public BufferImpl setMedium(int pos, int i) { ensureLength(pos + 3); buffer.setMedium(pos, i); return this; } - public Buffer setMediumLE(int pos, int i) { + public BufferImpl setMediumLE(int pos, int i) { ensureLength(pos + 3); buffer.setMediumLE(pos, i); return this; } - public Buffer setLong(int pos, long l) { + public BufferImpl setLong(int pos, long l) { ensureLength(pos + 8); buffer.setLong(pos, l); return this; } - public Buffer setLongLE(int pos, long l) { + public BufferImpl setLongLE(int pos, long l) { ensureLength(pos + 8); buffer.setLongLE(pos, l); return this; } - public Buffer setDouble(int pos, double d) { + public BufferImpl setDouble(int pos, double d) { ensureLength(pos + 8); buffer.setDouble(pos, d); return this; } - public Buffer setFloat(int pos, float f) { + public BufferImpl setFloat(int pos, float f) { ensureLength(pos + 4); buffer.setFloat(pos, f); return this; } - public Buffer setShort(int pos, short s) { + public BufferImpl setShort(int pos, short s) { ensureLength(pos + 2); buffer.setShort(pos, s); return this; } - public Buffer setShortLE(int pos, short s) { + public BufferImpl setShortLE(int pos, short s) { ensureLength(pos + 2); buffer.setShortLE(pos, s); return this; } - public Buffer setUnsignedShort(int pos, int s) { + public BufferImpl setUnsignedShort(int pos, int s) { ensureLength(pos + 2); buffer.setShort(pos, s); return this; } - public Buffer setUnsignedShortLE(int pos, int s) { + public BufferImpl setUnsignedShortLE(int pos, int s) { ensureLength(pos + 2); buffer.setShortLE(pos, s); return this; } - public Buffer setBuffer(int pos, Buffer buff) { + public BufferImpl setBuffer(int pos, Buffer buff) { ensureLength(pos + buff.length()); BufferImpl impl = (BufferImpl) buff; ByteBuf byteBuf = impl.buffer; @@ -479,7 +455,7 @@ public Buffer setBuffer(int pos, Buffer buff) { return this; } - public Buffer setBuffer(int pos, Buffer buffer, int offset, int len) { + public BufferImpl setBuffer(int pos, Buffer buffer, int offset, int len) { ensureLength(pos + len); BufferImpl impl = (BufferImpl) buffer; ByteBuf byteBuf = impl.buffer; @@ -493,23 +469,23 @@ public BufferImpl setBytes(int pos, ByteBuffer b) { return this; } - public Buffer setBytes(int pos, byte[] b) { + public BufferImpl setBytes(int pos, byte[] b) { ensureLength(pos + b.length); buffer.setBytes(pos, b); return this; } - public Buffer setBytes(int pos, byte[] b, int offset, int len) { + public BufferImpl setBytes(int pos, byte[] b, int offset, int len) { ensureLength(pos + len); buffer.setBytes(pos, b, offset, len); return this; } - public Buffer setString(int pos, String str) { + public BufferImpl setString(int pos, String str) { return setBytes(pos, str, CharsetUtil.UTF_8); } - public Buffer setString(int pos, String str, String enc) { + public BufferImpl setString(int pos, String str, String enc) { return setBytes(pos, str, Charset.forName(enc)); } @@ -517,15 +493,15 @@ public int length() { return buffer.writerIndex(); } - public Buffer copy() { + public BufferImpl copy() { return buffer.isReadOnly() ? this : new BufferImpl(buffer.copy()); } - public Buffer slice() { + public BufferImpl slice() { return new BufferImpl(buffer.slice()); } - public Buffer slice(int start, int end) { + public BufferImpl slice(int start, int end) { return new BufferImpl(buffer.slice(start, end - start)); } @@ -544,14 +520,14 @@ public ByteBuf getByteBuf() { return duplicate; } - private Buffer append(String str, Charset charset) { + private BufferImpl append(String str, Charset charset) { byte[] bytes = str.getBytes(charset); ensureExpandableBy(bytes.length); buffer.writeBytes(bytes); return this; } - private Buffer setBytes(int pos, String str, Charset charset) { + private BufferImpl setBytes(int pos, String str, Charset charset) { byte[] bytes = str.getBytes(charset); ensureLength(pos + bytes.length); buffer.setBytes(pos, bytes); diff --git a/src/main/java/io/vertx/core/buffer/impl/BufferInternal.java b/src/main/java/io/vertx/core/buffer/impl/BufferInternal.java new file mode 100644 index 00000000000..e698a5b6d69 --- /dev/null +++ b/src/main/java/io/vertx/core/buffer/impl/BufferInternal.java @@ -0,0 +1,203 @@ +package io.vertx.core.buffer.impl; + +import io.netty.buffer.ByteBuf; +import io.vertx.core.buffer.Buffer; + +import java.nio.ByteBuffer; +import java.util.Objects; + +public interface BufferInternal extends Buffer { + + /** + *

+ * Create a new buffer from a Netty {@code ByteBuf}. + * Note that the returned buffer is backed by given Netty ByteBuf, + * so changes in the returned buffer are reflected in given Netty ByteBuf, and vice-versa. + *

+ *

+ * For example, both buffers in the code below share their data: + *

+ *
+   *   Buffer src = Buffer.buffer();
+   *   Buffer clone = Buffer.buffer(src.getByteBuf());
+   * 
+ * + * @param byteBuf the Netty ByteBuf + * @return the buffer + */ + static BufferInternal buffer(ByteBuf byteBuf) { + Objects.requireNonNull(byteBuf); + return new BufferImpl(byteBuf); + } + + static BufferInternal buffer(int initialSizeHint) { + return new BufferImpl(initialSizeHint); + } + + static BufferInternal buffer() { + return new BufferImpl(); + } + + static BufferInternal buffer(String str) { + return new BufferImpl(str); + } + + static BufferInternal buffer(String str, String enc) { + return new BufferImpl(str, enc); + } + + static BufferInternal buffer(byte[] bytes) { + return new BufferImpl(bytes); + } + + @Override + BufferInternal appendBuffer(Buffer buff); + + @Override + BufferInternal appendBuffer(Buffer buff, int offset, int len); + + @Override + BufferInternal appendBytes(byte[] bytes); + + @Override + BufferInternal appendBytes(byte[] bytes, int offset, int len); + + @Override + BufferInternal appendByte(byte b); + + @Override + BufferInternal appendUnsignedByte(short b); + + @Override + BufferInternal appendInt(int i); + + @Override + BufferInternal appendIntLE(int i); + + @Override + BufferInternal appendUnsignedInt(long i); + + @Override + BufferInternal appendUnsignedIntLE(long i); + + @Override + BufferInternal appendMedium(int i); + + @Override + BufferInternal appendMediumLE(int i); + + @Override + BufferInternal appendLong(long l); + + @Override + BufferInternal appendLongLE(long l); + + @Override + BufferInternal appendShort(short s); + + @Override + BufferInternal appendShortLE(short s); + + @Override + BufferInternal appendUnsignedShort(int s); + + @Override + BufferInternal appendUnsignedShortLE(int s); + + @Override + BufferInternal appendFloat(float f); + + @Override + BufferInternal appendDouble(double d); + + @Override + BufferInternal appendString(String str, String enc); + + @Override + BufferInternal appendString(String str); + + @Override + BufferInternal setByte(int pos, byte b); + + @Override + BufferInternal setUnsignedByte(int pos, short b); + + @Override + BufferInternal setInt(int pos, int i); + + @Override + BufferInternal setIntLE(int pos, int i); + + @Override + BufferInternal setUnsignedInt(int pos, long i); + + @Override + BufferInternal setUnsignedIntLE(int pos, long i); + + @Override + BufferInternal setMedium(int pos, int i); + + @Override + BufferInternal setMediumLE(int pos, int i); + + @Override + BufferInternal setLong(int pos, long l); + + @Override + BufferInternal setLongLE(int pos, long l); + + @Override + BufferInternal setDouble(int pos, double d); + + @Override + BufferInternal setFloat(int pos, float f); + + @Override + BufferInternal setShort(int pos, short s); + + @Override + BufferInternal setShortLE(int pos, short s); + + @Override + BufferInternal setUnsignedShort(int pos, int s); + + @Override + BufferInternal setUnsignedShortLE(int pos, int s); + + @Override + BufferInternal setBuffer(int pos, Buffer b); + + @Override + BufferInternal setBuffer(int pos, Buffer b, int offset, int len); + + @Override + BufferInternal setBytes(int pos, ByteBuffer b); + + @Override + BufferInternal setBytes(int pos, byte[] b); + + @Override + BufferInternal setBytes(int pos, byte[] b, int offset, int len); + + @Override + BufferInternal setString(int pos, String str); + + @Override + BufferInternal setString(int pos, String str, String enc); + + @Override + BufferInternal copy(); + + @Override + BufferInternal slice(); + + @Override + BufferInternal slice(int start, int end); + + /** + * Returns the Buffer as a Netty {@code ByteBuf}. + * + *

The returned buffer is a duplicate that maintain its own indices. + */ + ByteBuf getByteBuf(); +} diff --git a/src/main/java/io/vertx/core/datagram/impl/DatagramSocketImpl.java b/src/main/java/io/vertx/core/datagram/impl/DatagramSocketImpl.java index 0c33d3bc8c4..34145d17b7f 100644 --- a/src/main/java/io/vertx/core/datagram/impl/DatagramSocketImpl.java +++ b/src/main/java/io/vertx/core/datagram/impl/DatagramSocketImpl.java @@ -27,6 +27,7 @@ import io.vertx.core.Handler; import io.vertx.core.Promise; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.datagram.DatagramSocket; import io.vertx.core.datagram.DatagramSocketOptions; import io.vertx.core.impl.AddressResolver; @@ -266,7 +267,7 @@ public Future send(Buffer packet, int port, String host) { io.netty.util.concurrent.Future f1 = resolver.resolveHostname(context.nettyEventLoop(), host); f1.addListener((GenericFutureListener>) res1 -> { if (res1.isSuccess()) { - ChannelFuture f2 = channel.writeAndFlush(new DatagramPacket(packet.getByteBuf(), new InetSocketAddress(f1.getNow().getAddress(), port))); + ChannelFuture f2 = channel.writeAndFlush(new DatagramPacket(((BufferInternal)packet).getByteBuf(), new InetSocketAddress(f1.getNow().getAddress(), port))); if (metrics != null) { f2.addListener(fut -> { if (fut.isSuccess()) { @@ -384,7 +385,7 @@ public void handleMessage(Object msg) { if (content.isDirect()) { content = VertxHandler.safeBuffer(content); } - handlePacket(new DatagramPacketImpl(packet.sender(), Buffer.buffer(content))); + handlePacket(new DatagramPacketImpl(packet.sender(), BufferInternal.buffer(content))); } } diff --git a/src/main/java/io/vertx/core/file/impl/AsyncFileImpl.java b/src/main/java/io/vertx/core/file/impl/AsyncFileImpl.java index c2524054bd6..d9242d96854 100644 --- a/src/main/java/io/vertx/core/file/impl/AsyncFileImpl.java +++ b/src/main/java/io/vertx/core/file/impl/AsyncFileImpl.java @@ -17,6 +17,8 @@ import io.vertx.core.Handler; import io.vertx.core.Promise; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferImpl; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.file.AsyncFile; import io.vertx.core.file.AsyncFileLock; import io.vertx.core.file.FileSystemException; @@ -203,7 +205,7 @@ private synchronized void doWrite(Buffer buffer, long position, Handler 1) { doWrite(buf.nioBuffers(), position, wrapped); } else { diff --git a/src/main/java/io/vertx/core/http/impl/Http1xClientConnection.java b/src/main/java/io/vertx/core/http/impl/Http1xClientConnection.java index 952c16a6666..49957f2f17d 100644 --- a/src/main/java/io/vertx/core/http/impl/Http1xClientConnection.java +++ b/src/main/java/io/vertx/core/http/impl/Http1xClientConnection.java @@ -60,6 +60,7 @@ import io.vertx.core.Promise; import io.vertx.core.VertxException; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.HttpClientOptions; import io.vertx.core.http.HttpFrame; import io.vertx.core.http.HttpMethod; @@ -936,7 +937,7 @@ private void removeChannelHandlers() { } private void handleResponseChunk(Stream stream, ByteBuf chunk) { - Buffer buff = Buffer.buffer(VertxHandler.safeBuffer(chunk)); + Buffer buff = BufferInternal.buffer(VertxHandler.safeBuffer(chunk)); int len = buff.length(); receiveBytes(len); stream.bytesRead += len; diff --git a/src/main/java/io/vertx/core/http/impl/Http1xServerConnection.java b/src/main/java/io/vertx/core/http/impl/Http1xServerConnection.java index 4d373bb92a6..da29d683966 100644 --- a/src/main/java/io/vertx/core/http/impl/Http1xServerConnection.java +++ b/src/main/java/io/vertx/core/http/impl/Http1xServerConnection.java @@ -44,6 +44,7 @@ import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.HttpServerOptions; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.ServerWebSocket; @@ -192,7 +193,7 @@ private void onContent(Object msg) { handleError(content); return; } - Buffer buffer = Buffer.buffer(VertxHandler.safeBuffer(content.content())); + Buffer buffer = BufferInternal.buffer(VertxHandler.safeBuffer(content.content())); Http1xServerRequest request; synchronized (this) { request = requestInProgress; diff --git a/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java b/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java index 8327cdcd2e9..a8b75ff6450 100644 --- a/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java +++ b/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java @@ -22,6 +22,7 @@ import io.vertx.core.Handler; import io.vertx.core.MultiMap; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.*; import io.vertx.core.http.Cookie; import io.vertx.core.http.HttpVersion; @@ -447,7 +448,7 @@ Future webSocket() { * Handle the request when a WebSocket upgrade header is present. */ private void webSocket(PromiseInternal promise) { - Buffer body = Buffer.buffer(); + BufferInternal body = BufferInternal.buffer(); boolean[] failed = new boolean[1]; handler(buff -> { if (!failed[0]) { @@ -548,7 +549,7 @@ private void onData(Buffer data) { bytesRead += data.length(); if (decoder != null) { try { - decoder.offer(new DefaultHttpContent(data.getByteBuf())); + decoder.offer(new DefaultHttpContent(((BufferInternal)data).getByteBuf())); } catch (HttpPostRequestDecoder.ErrorDataDecoderException e) { handleException(e); } diff --git a/src/main/java/io/vertx/core/http/impl/Http1xServerResponse.java b/src/main/java/io/vertx/core/http/impl/Http1xServerResponse.java index f5c6530e9c1..a8f3926a411 100644 --- a/src/main/java/io/vertx/core/http/impl/Http1xServerResponse.java +++ b/src/main/java/io/vertx/core/http/impl/Http1xServerResponse.java @@ -30,6 +30,7 @@ import io.vertx.core.MultiMap; import io.vertx.core.Promise; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.Cookie; import io.vertx.core.http.HttpClosedException; import io.vertx.core.http.HttpHeaders; @@ -67,7 +68,7 @@ */ public class Http1xServerResponse implements HttpServerResponse, HttpResponse { - private static final Buffer EMPTY_BUFFER = Buffer.buffer(Unpooled.EMPTY_BUFFER); + private static final Buffer EMPTY_BUFFER = BufferInternal.buffer(Unpooled.EMPTY_BUFFER); private static final Logger log = LoggerFactory.getLogger(Http1xServerResponse.class); private static final String RESPONSE_WRITTEN = "Response has already been written"; @@ -323,21 +324,21 @@ public HttpServerResponse endHandler(@Nullable Handler handler) { @Override public Future write(Buffer chunk) { PromiseInternal promise = context.promise(); - write(chunk.getByteBuf(), promise); + write(((BufferInternal)chunk).getByteBuf(), promise); return promise.future(); } @Override public Future write(String chunk, String enc) { PromiseInternal promise = context.promise(); - write(Buffer.buffer(chunk, enc).getByteBuf(), promise); + write(BufferInternal.buffer(chunk, enc).getByteBuf(), promise); return promise.future(); } @Override public Future write(String chunk) { PromiseInternal promise = context.promise(); - write(Buffer.buffer(chunk).getByteBuf(), promise); + write(BufferInternal.buffer(chunk).getByteBuf(), promise); return promise.future(); } @@ -388,7 +389,7 @@ private void end(Buffer chunk, PromiseInternal listener) { throw new IllegalStateException(RESPONSE_WRITTEN); } written = true; - ByteBuf data = chunk.getByteBuf(); + ByteBuf data = ((BufferInternal)chunk).getByteBuf(); bytesWritten += data.readableBytes(); HttpObject msg; if (!headWritten) { diff --git a/src/main/java/io/vertx/core/http/impl/Http2ConnectionBase.java b/src/main/java/io/vertx/core/http/impl/Http2ConnectionBase.java index 6b5bb9b3da0..7320a51fe39 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ConnectionBase.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ConnectionBase.java @@ -29,6 +29,7 @@ import io.vertx.core.Promise; import io.vertx.core.VertxException; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.buffer.impl.VertxByteBufAllocator; import io.vertx.core.http.GoAway; import io.vertx.core.http.HttpClosedException; @@ -291,7 +292,7 @@ public void onUnknownFrame(ChannelHandlerContext ctx, byte frameType, int stream Http2Flags flags, ByteBuf payload) { VertxHttp2Stream stream = stream(streamId); if (stream != null) { - Buffer buff = Buffer.buffer(safeBuffer(payload)); + Buffer buff = BufferInternal.buffer(safeBuffer(payload)); stream.onCustomFrame(new HttpFrameImpl(frameType, flags.value(), buff)); } } @@ -309,7 +310,7 @@ public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int VertxHttp2Stream stream = stream(streamId); if (stream != null) { data = safeBuffer(data); - Buffer buff = Buffer.buffer(data); + Buffer buff = BufferInternal.buffer(data); stream.onData(buff); if (endOfStream) { stream.onEnd(); @@ -344,7 +345,7 @@ public HttpConnection goAway(long errorCode, int lastStreamId, Buffer debugData) if (lastStreamId < 0) { lastStreamId = handler.connection().remote().lastStreamCreated(); } - handler.writeGoAway(errorCode, lastStreamId, debugData != null ? debugData.getByteBuf() : Unpooled.EMPTY_BUFFER); + handler.writeGoAway(errorCode, lastStreamId, debugData != null ? ((BufferInternal)debugData).getByteBuf() : Unpooled.EMPTY_BUFFER); return this; } diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerRequest.java b/src/main/java/io/vertx/core/http/impl/Http2ServerRequest.java index 2f592427e78..3031a90fa11 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerRequest.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerRequest.java @@ -27,6 +27,7 @@ import io.vertx.core.Handler; import io.vertx.core.MultiMap; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.Cookie; import io.vertx.core.http.HttpConnection; import io.vertx.core.http.HttpMethod; @@ -152,7 +153,7 @@ public void handleCustomFrame(HttpFrame frame) { public void handleData(Buffer data) { if (postRequestDecoder != null) { try { - postRequestDecoder.offer(new DefaultHttpContent(data.getByteBuf())); + postRequestDecoder.offer(new DefaultHttpContent(((BufferInternal)data).getByteBuf())); } catch (Exception e) { handleException(e); } diff --git a/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java b/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java index 1d7f2f9e500..583044f9ea9 100644 --- a/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java +++ b/src/main/java/io/vertx/core/http/impl/Http2ServerResponse.java @@ -25,6 +25,7 @@ import io.vertx.core.MultiMap; import io.vertx.core.Promise; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.Cookie; import io.vertx.core.http.HttpHeaders; import io.vertx.core.http.HttpMethod; @@ -340,18 +341,18 @@ public Future writeEarlyHints(MultiMap headers) { @Override public Future write(Buffer chunk) { - ByteBuf buf = chunk.getByteBuf(); + ByteBuf buf = ((BufferInternal)chunk).getByteBuf(); return write(buf, false); } @Override public Future write(String chunk, String enc) { - return write(Buffer.buffer(chunk, enc).getByteBuf(), false); + return write(BufferInternal.buffer(chunk, enc).getByteBuf(), false); } @Override public Future write(String chunk) { - return write(Buffer.buffer(chunk).getByteBuf(), false); + return write(BufferInternal.buffer(chunk).getByteBuf(), false); } @Override @@ -366,7 +367,7 @@ public Future end(String chunk, String enc) { @Override public Future end(Buffer chunk) { - return write(chunk.getByteBuf(), true); + return write(((BufferInternal)chunk).getByteBuf(), true); } @Override @@ -488,7 +489,7 @@ public Future writeCustomFrame(int type, int flags, Buffer payload) { synchronized (conn) { checkValid(); checkSendHeaders(false); - stream.writeFrame(type, flags, payload.getByteBuf(), promise); + stream.writeFrame(type, flags, ((BufferInternal)payload).getByteBuf(), promise); } return promise.future(); } diff --git a/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl.java b/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl.java index 4976642aac2..a3f61d5ddff 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl.java +++ b/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl.java @@ -15,6 +15,7 @@ import io.vertx.codegen.annotations.Nullable; import io.vertx.core.*; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.*; import io.vertx.core.http.impl.headers.HeadersMultiMap; import io.vertx.core.impl.Arguments; @@ -267,7 +268,7 @@ public Future writeCustomFrame(int type, int flags, Buffer payload) { synchronized (this) { checkEnded(); } - return stream.writeFrame(type, flags, payload.getByteBuf()); + return stream.writeFrame(type, flags, ((BufferInternal)payload).getByteBuf()); } private void handleDrained(Void v) { @@ -353,18 +354,18 @@ void handleResponse(Promise promise, HttpClientResponse resp @Override public Future end(String chunk) { - return write(Buffer.buffer(chunk).getByteBuf(), true); + return write(BufferInternal.buffer(chunk).getByteBuf(), true); } @Override public Future end(String chunk, String enc) { Objects.requireNonNull(enc, "no null encoding accepted"); - return write(Buffer.buffer(chunk, enc).getByteBuf(), true); + return write(BufferInternal.buffer(chunk, enc).getByteBuf(), true); } @Override public Future end(Buffer chunk) { - return write(chunk.getByteBuf(), true); + return write(((BufferInternal)chunk).getByteBuf(), true); } @Override @@ -374,19 +375,19 @@ public Future end() { @Override public Future write(Buffer chunk) { - ByteBuf buf = chunk.getByteBuf(); + ByteBuf buf = ((BufferInternal)chunk).getByteBuf(); return write(buf, false); } @Override public Future write(String chunk) { - return write(Buffer.buffer(chunk).getByteBuf(), false); + return write(BufferInternal.buffer(chunk).getByteBuf(), false); } @Override public Future write(String chunk, String enc) { Objects.requireNonNull(enc, "no null encoding accepted"); - return write(Buffer.buffer(chunk, enc).getByteBuf(), false); + return write(BufferInternal.buffer(chunk, enc).getByteBuf(), false); } private boolean requiresContentLength() { diff --git a/src/main/java/io/vertx/core/http/impl/HttpClientStream.java b/src/main/java/io/vertx/core/http/impl/HttpClientStream.java index 183db464594..aa1c825cbd9 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpClientStream.java +++ b/src/main/java/io/vertx/core/http/impl/HttpClientStream.java @@ -17,6 +17,7 @@ import io.vertx.core.Handler; import io.vertx.core.MultiMap; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.HttpFrame; import io.vertx.core.http.HttpVersion; import io.vertx.core.http.StreamPriority; @@ -57,12 +58,12 @@ public interface HttpClientStream extends WriteStream { @Override default Future write(Buffer data) { - return writeBuffer(data.getByteBuf(), false); + return writeBuffer(((BufferInternal)data).getByteBuf(), false); } @Override default Future end(Buffer data) { - return writeBuffer(data.getByteBuf(), true); + return writeBuffer(((BufferInternal)data).getByteBuf(), true); } @Override diff --git a/src/main/java/io/vertx/core/http/impl/NettyFileUpload.java b/src/main/java/io/vertx/core/http/impl/NettyFileUpload.java index a81c5f56724..0cd0e7c3905 100644 --- a/src/main/java/io/vertx/core/http/impl/NettyFileUpload.java +++ b/src/main/java/io/vertx/core/http/impl/NettyFileUpload.java @@ -17,6 +17,7 @@ import io.vertx.core.Context; import io.vertx.core.Handler; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.streams.ReadStream; import io.vertx.core.streams.impl.InboundBuffer; @@ -138,13 +139,13 @@ public void handleException(Throwable err) { @Override public void setContent(ByteBuf channelBuffer) throws IOException { completed = true; - receiveData(Buffer.buffer(channelBuffer)); + receiveData(BufferInternal.buffer(channelBuffer)); end(); } @Override public void addContent(ByteBuf channelBuffer, boolean last) throws IOException { - receiveData(Buffer.buffer(channelBuffer)); + receiveData(BufferInternal.buffer(channelBuffer)); if (last) { completed = true; end(); diff --git a/src/main/java/io/vertx/core/http/impl/VertxHttp2ConnectionHandler.java b/src/main/java/io/vertx/core/http/impl/VertxHttp2ConnectionHandler.java index ffb76a449f8..2f23b3919da 100644 --- a/src/main/java/io/vertx/core/http/impl/VertxHttp2ConnectionHandler.java +++ b/src/main/java/io/vertx/core/http/impl/VertxHttp2ConnectionHandler.java @@ -24,6 +24,7 @@ import io.netty.util.concurrent.Promise; import io.vertx.core.Handler; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.GoAway; import io.vertx.core.net.impl.ShutdownEvent; import io.vertx.core.net.impl.ConnectionBase; @@ -210,12 +211,12 @@ public void onStreamRemoved(Http2Stream stream) { @Override public void onGoAwaySent(int lastStreamId, long errorCode, ByteBuf debugData) { - connection.onGoAwaySent(new GoAway().setErrorCode(errorCode).setLastStreamId(lastStreamId).setDebugData(Buffer.buffer(debugData))); + connection.onGoAwaySent(new GoAway().setErrorCode(errorCode).setLastStreamId(lastStreamId).setDebugData(BufferInternal.buffer(debugData))); } @Override public void onGoAwayReceived(int lastStreamId, long errorCode, ByteBuf debugData) { - connection.onGoAwayReceived(new GoAway().setErrorCode(errorCode).setLastStreamId(lastStreamId).setDebugData(Buffer.buffer(debugData))); + connection.onGoAwayReceived(new GoAway().setErrorCode(errorCode).setLastStreamId(lastStreamId).setDebugData(BufferInternal.buffer(debugData))); } // diff --git a/src/main/java/io/vertx/core/http/impl/WebSocketHandshakeInboundHandler.java b/src/main/java/io/vertx/core/http/impl/WebSocketHandshakeInboundHandler.java index 89d57a4f330..2a7c0b0fc6a 100644 --- a/src/main/java/io/vertx/core/http/impl/WebSocketHandshakeInboundHandler.java +++ b/src/main/java/io/vertx/core/http/impl/WebSocketHandshakeInboundHandler.java @@ -25,6 +25,7 @@ import io.netty.util.concurrent.GenericFutureListener; import io.netty.util.concurrent.Promise; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.UpgradeRejectedException; import io.vertx.core.http.impl.headers.HeadersAdaptor; @@ -112,7 +113,7 @@ private HttpHeaders handshakeComplete(FullHttpResponse response) throws UpgradeR msg, sc, new HeadersAdaptor(response.headers()), - content != null ? Buffer.buffer(content) : null); + content != null ? BufferInternal.buffer(content) : null); } else { handshaker.finishHandshake(chctx.channel(), response); return response.headers(); diff --git a/src/main/java/io/vertx/core/http/impl/WebSocketImplBase.java b/src/main/java/io/vertx/core/http/impl/WebSocketImplBase.java index 06510b8e513..f2429d813c5 100644 --- a/src/main/java/io/vertx/core/http/impl/WebSocketImplBase.java +++ b/src/main/java/io/vertx/core/http/impl/WebSocketImplBase.java @@ -27,6 +27,7 @@ import io.vertx.core.MultiMap; import io.vertx.core.Promise; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.eventbus.EventBus; import io.vertx.core.eventbus.Message; import io.vertx.core.eventbus.MessageConsumer; @@ -307,7 +308,7 @@ private Future writePartialMessage(WebSocketFrameType frameType, Buffer da Buffer slice = data.slice(offset, end); WebSocketFrame frame; if (offset == 0 || !supportsContinuation) { - frame = new WebSocketFrameImpl(frameType, slice.getByteBuf(), isFinal); + frame = new WebSocketFrameImpl(frameType, ((BufferInternal)slice).getByteBuf(), isFinal); } else { frame = WebSocketFrame.continuationFrame(slice, isFinal); } @@ -333,7 +334,7 @@ public Future writeFrame(WebSocketFrame frame) { } private void writeBinaryFrameInternal(Buffer data) { - writeFrame(new WebSocketFrameImpl(WebSocketFrameType.BINARY, data.getByteBuf())); + writeFrame(new WebSocketFrameImpl(WebSocketFrameType.BINARY, ((BufferInternal)data).getByteBuf())); } private void writeTextFrameInternal(String str) { @@ -525,7 +526,7 @@ public void handle(WebSocketFrameInternal frame) { } private void handleTextFrame(WebSocketFrameInternal frame) { - Buffer frameBuffer = Buffer.buffer(frame.getBinaryData()); + Buffer frameBuffer = BufferInternal.buffer(frame.getBinaryData()); if (textMessageBuffer == null) { textMessageBuffer = frameBuffer; } else { @@ -549,7 +550,7 @@ private void handleTextFrame(WebSocketFrameInternal frame) { } private void handleBinaryFrame(WebSocketFrameInternal frame) { - Buffer frameBuffer = Buffer.buffer(frame.getBinaryData()); + Buffer frameBuffer = BufferInternal.buffer(frame.getBinaryData()); if (binaryMessageBuffer == null) { binaryMessageBuffer = frameBuffer; } else { diff --git a/src/main/java/io/vertx/core/http/impl/ws/WebSocketFrameImpl.java b/src/main/java/io/vertx/core/http/impl/ws/WebSocketFrameImpl.java index bf58f275a3e..799f914eff6 100644 --- a/src/main/java/io/vertx/core/http/impl/ws/WebSocketFrameImpl.java +++ b/src/main/java/io/vertx/core/http/impl/ws/WebSocketFrameImpl.java @@ -16,6 +16,7 @@ import io.netty.util.CharsetUtil; import io.netty.util.ReferenceCounted; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.WebSocketFrame; import io.vertx.core.http.WebSocketFrameType; @@ -31,7 +32,7 @@ public class WebSocketFrameImpl implements WebSocketFrameInternal, ReferenceCounted { public static WebSocketFrame binaryFrame(Buffer data, boolean isFinal) { - return new WebSocketFrameImpl(WebSocketFrameType.BINARY, data.getByteBuf(), isFinal); + return new WebSocketFrameImpl(WebSocketFrameType.BINARY, ((BufferInternal)data).getByteBuf(), isFinal); } public static WebSocketFrame textFrame(String str, boolean isFinal) { @@ -39,15 +40,15 @@ public static WebSocketFrame textFrame(String str, boolean isFinal) { } public static WebSocketFrame continuationFrame(Buffer data, boolean isFinal) { - return new WebSocketFrameImpl(WebSocketFrameType.CONTINUATION, data.getByteBuf(), isFinal); + return new WebSocketFrameImpl(WebSocketFrameType.CONTINUATION, ((BufferInternal)data).getByteBuf(), isFinal); } public static WebSocketFrame pingFrame(Buffer data) { - return new WebSocketFrameImpl(WebSocketFrameType.PING, data.getByteBuf(), true); + return new WebSocketFrameImpl(WebSocketFrameType.PING, ((BufferInternal)data).getByteBuf(), true); } public static WebSocketFrame pongFrame(Buffer data) { - return new WebSocketFrameImpl(WebSocketFrameType.PONG, data.getByteBuf(), true); + return new WebSocketFrameImpl(WebSocketFrameType.PONG, ((BufferInternal)data).getByteBuf(), true); } private final WebSocketFrameType type; @@ -145,7 +146,7 @@ public String textData() { } public Buffer binaryData() { - return Buffer.buffer(binaryData); + return BufferInternal.buffer(binaryData); } public void setBinaryData(ByteBuf binaryData) { diff --git a/src/main/java/io/vertx/core/impl/VertxInternal.java b/src/main/java/io/vertx/core/impl/VertxInternal.java index fdcd5a595b2..55affe67bdd 100644 --- a/src/main/java/io/vertx/core/impl/VertxInternal.java +++ b/src/main/java/io/vertx/core/impl/VertxInternal.java @@ -166,6 +166,13 @@ default Future executeBlockingInternal(Callable blockingCodeHandler, b */ FileResolver fileResolver(); + /** + * Return the Netty EventLoopGroup used by Vert.x + * + * @return the EventLoopGroup + */ + EventLoopGroup nettyEventLoopGroup(); + /** * @return the Netty {@code AddressResolverGroup} to use in a Netty {@code Bootstrap} */ diff --git a/src/main/java/io/vertx/core/json/jackson/DatabindCodec.java b/src/main/java/io/vertx/core/json/jackson/DatabindCodec.java index 46014ab07b4..7b1360af53a 100644 --- a/src/main/java/io/vertx/core/json/jackson/DatabindCodec.java +++ b/src/main/java/io/vertx/core/json/jackson/DatabindCodec.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.module.SimpleModule; import io.netty.buffer.ByteBufInputStream; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.json.DecodeException; import io.vertx.core.json.EncodeException; import io.vertx.core.json.JsonArray; @@ -103,7 +104,7 @@ public T fromBuffer(Buffer buf, TypeReference typeRef) throws DecodeExcep return fromParser(createParser(buf), typeRef); } - public static JsonParser createParser(Buffer buf) { + public static JsonParser createParser(BufferInternal buf) { try { return DatabindCodec.mapper.getFactory().createParser((InputStream) new ByteBufInputStream(buf.getByteBuf())); } catch (IOException e) { diff --git a/src/main/java/io/vertx/core/json/jackson/JacksonCodec.java b/src/main/java/io/vertx/core/json/jackson/JacksonCodec.java index 935ee591532..9f35ad5dbd8 100644 --- a/src/main/java/io/vertx/core/json/jackson/JacksonCodec.java +++ b/src/main/java/io/vertx/core/json/jackson/JacksonCodec.java @@ -22,6 +22,7 @@ import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.Unpooled; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.json.DecodeException; import io.vertx.core.json.EncodeException; import io.vertx.core.json.JsonArray; @@ -113,7 +114,7 @@ public Buffer toBuffer(Object object, boolean pretty) throws EncodeException { try { encodeJson(object, generator); generator.flush(); - return Buffer.buffer(buf); + return BufferInternal.buffer(buf); } catch (IOException e) { throw new EncodeException(e.getMessage(), e); } finally { @@ -131,7 +132,7 @@ public static JsonParser createParser(String str) { public static JsonParser createParser(Buffer buf) { try { - return factory.createParser((InputStream) new ByteBufInputStream(buf.getByteBuf())); + return factory.createParser((InputStream) new ByteBufInputStream(((BufferInternal)buf).getByteBuf())); } catch (IOException e) { throw new DecodeException("Failed to decode:" + e.getMessage(), e); } diff --git a/src/main/java/io/vertx/core/net/impl/NetSocketImpl.java b/src/main/java/io/vertx/core/net/impl/NetSocketImpl.java index 90802a526df..d0ac6a8b80c 100644 --- a/src/main/java/io/vertx/core/net/impl/NetSocketImpl.java +++ b/src/main/java/io/vertx/core/net/impl/NetSocketImpl.java @@ -24,6 +24,7 @@ import io.vertx.core.Handler; import io.vertx.core.Promise; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.eventbus.Message; import io.vertx.core.eventbus.MessageConsumer; import io.vertx.core.impl.ContextInternal; @@ -142,7 +143,7 @@ public String applicationLayerProtocol() { @Override public Future write(Buffer data) { - return writeMessage(data.getByteBuf()); + return writeMessage(((BufferInternal)data).getByteBuf()); } @Override @@ -324,7 +325,7 @@ public void handle(Object msg) { if (msg instanceof ByteBuf) { msg = VertxHandler.safeBuffer((ByteBuf) msg); ByteBuf byteBuf = (ByteBuf) msg; - Buffer buffer = Buffer.buffer(byteBuf); + Buffer buffer = BufferInternal.buffer(byteBuf); if (!pending.write(buffer)) { doPause(); } diff --git a/src/main/java/io/vertx/core/parsetools/impl/RecordParserImpl.java b/src/main/java/io/vertx/core/parsetools/impl/RecordParserImpl.java index 5ada3d52643..e727dc60994 100644 --- a/src/main/java/io/vertx/core/parsetools/impl/RecordParserImpl.java +++ b/src/main/java/io/vertx/core/parsetools/impl/RecordParserImpl.java @@ -14,6 +14,7 @@ import io.netty.buffer.Unpooled; import io.vertx.core.Handler; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.impl.Arguments; import io.vertx.core.parsetools.RecordParser; import io.vertx.core.streams.ReadStream; @@ -27,7 +28,7 @@ public class RecordParserImpl implements RecordParser { // Empty and unmodifiable - private static final Buffer EMPTY_BUFFER = Buffer.buffer(Unpooled.EMPTY_BUFFER); + private static final Buffer EMPTY_BUFFER = BufferInternal.buffer(Unpooled.EMPTY_BUFFER); private Buffer buff = EMPTY_BUFFER; private int pos; // Current position in buffer diff --git a/src/test/java/io/vertx/core/EventLoopGroupTest.java b/src/test/java/io/vertx/core/EventLoopGroupTest.java deleted file mode 100644 index d0682cc1c51..00000000000 --- a/src/test/java/io/vertx/core/EventLoopGroupTest.java +++ /dev/null @@ -1,28 +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.netty.channel.EventLoopGroup; -import io.vertx.test.core.VertxTestBase; -import org.junit.Test; - -/** - * @author Tim Fox - */ -public class EventLoopGroupTest extends VertxTestBase { - - @Test - public void testGetEventLoopGroup() { - EventLoopGroup elp = vertx.nettyEventLoopGroup(); - assertNotNull(elp); - } -} diff --git a/src/test/java/io/vertx/core/buffer/BufferTest.java b/src/test/java/io/vertx/core/buffer/BufferTest.java index d18a7752fa5..2cba92938f7 100644 --- a/src/test/java/io/vertx/core/buffer/BufferTest.java +++ b/src/test/java/io/vertx/core/buffer/BufferTest.java @@ -15,6 +15,7 @@ import io.netty.buffer.Unpooled; import io.netty.util.IllegalReferenceCountException; import io.vertx.core.buffer.impl.BufferImpl; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.json.DecodeException; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; @@ -42,14 +43,14 @@ private static ByteBuf paddedByteBuf(int padding, byte[] bytes) { } private static final int MEDIUM_MAX_VALUE = 2 << 23; - private static final Function PADDED_BUFFER_FACTORY = arr -> Buffer.buffer(paddedByteBuf(5, arr)); + private static final Function PADDED_BUFFER_FACTORY = arr -> BufferInternal.buffer(paddedByteBuf(5, arr)); @Test public void testConstructorArguments() throws Exception { assertIllegalArgumentException(() -> Buffer.buffer(-1)); assertNullPointerException(() -> Buffer.buffer((byte[]) null)); assertNullPointerException(() -> Buffer.buffer((String) null)); - assertNullPointerException(() -> Buffer.buffer((ByteBuf) null)); + assertNullPointerException(() -> BufferInternal.buffer((ByteBuf) null)); assertNullPointerException(() -> Buffer.buffer(null, "UTF-8")); assertNullPointerException(() -> Buffer.buffer("", null)); } @@ -1026,7 +1027,7 @@ public void testSlice1() throws Exception { assertEquals(rand, buff.getLong(0)); buff.appendString(TestUtils.randomUnicodeString(100)); assertEquals(100, sliced.length()); - ByteBuf duplicate = sliced.getByteBuf(); + ByteBuf duplicate = ((BufferInternal)sliced).getByteBuf(); assertEquals(0, duplicate.readerIndex()); assertEquals(100, duplicate.readableBytes()); for (int i = 0; i < 100; i++) { @@ -1051,7 +1052,7 @@ public void testSlice2() throws Exception { assertEquals(rand, buff.getLong(10)); buff.appendString(TestUtils.randomUnicodeString(100)); assertEquals(10, sliced.length()); - ByteBuf duplicate = sliced.getByteBuf(); + ByteBuf duplicate = ((BufferInternal)sliced).getByteBuf(); assertEquals(0, duplicate.readerIndex()); assertEquals(10, duplicate.readableBytes()); for (int i = 0; i < 10; i++) { @@ -1101,14 +1102,14 @@ public void testToJsonArray() throws Exception { @Test public void testLength() throws Exception { byte[] bytes = TestUtils.randomByteArray(100); - Buffer buffer = Buffer.buffer(bytes); - assertEquals(100, Buffer.buffer(buffer.getByteBuf()).length()); + BufferInternal buffer = BufferInternal.buffer(bytes); + assertEquals(100, BufferInternal.buffer(buffer.getByteBuf()).length()); } @Test public void testLength2() throws Exception { byte[] bytes = TestUtils.randomByteArray(100); - assertEquals(90, Buffer.buffer(Unpooled.copiedBuffer(bytes).slice(10, 90)).length()); + assertEquals(90, BufferInternal.buffer(Unpooled.copiedBuffer(bytes).slice(10, 90)).length()); } @Test @@ -1116,7 +1117,7 @@ public void testAppendDoesNotModifyByteBufIndex() throws Exception { ByteBuf buf = Unpooled.copiedBuffer("foobar".getBytes()); assertEquals(0, buf.readerIndex()); assertEquals(6, buf.writerIndex()); - Buffer buffer = Buffer.buffer(buf); + Buffer buffer = BufferInternal.buffer(buf); Buffer other = Buffer.buffer("prefix"); other.appendBuffer(buffer); assertEquals(0, buf.readerIndex()); @@ -1126,7 +1127,7 @@ public void testAppendDoesNotModifyByteBufIndex() throws Exception { @Test public void testAppendExpandsBufferWhenMaxCapacityReached() { - Buffer buff = Buffer.buffer(Unpooled.buffer(0, 8)); + Buffer buff = BufferInternal.buffer(Unpooled.buffer(0, 8)); buff.appendString("Hello World"); } @@ -1134,7 +1135,7 @@ public void testAppendExpandsBufferWhenMaxCapacityReached() { public void testWriteExpandsBufferWhenMaxCapacityReached() { String s = "Hello World"; ByteBuf byteBuf = Unpooled.buffer(0, s.length() - 1); - Buffer buff = Buffer.buffer(byteBuf); + Buffer buff = BufferInternal.buffer(byteBuf); int idx = 0; for (byte b : s.getBytes()) { buff.setByte(idx++, b); @@ -1145,7 +1146,7 @@ public void testWriteExpandsBufferWhenMaxCapacityReached() { public void testSetByteAfterCurrentWriterIndexWithoutExpandingCapacity() { ByteBuf byteBuf = Unpooled.buffer(10, Integer.MAX_VALUE); byteBuf.writerIndex(5); - Buffer buff = Buffer.buffer(byteBuf); + Buffer buff = BufferInternal.buffer(byteBuf); buff.setByte(7, (byte)1); assertEquals(8, buff.length()); } @@ -1154,7 +1155,7 @@ public void testSetByteAfterCurrentWriterIndexWithoutExpandingCapacity() { public void testGetByteBuf() { ByteBuf byteBuf = Unpooled.buffer(); byteBuf.writeCharSequence("Hello World", StandardCharsets.UTF_8); - Buffer buff = Buffer.buffer(byteBuf); + BufferInternal buff = BufferInternal.buffer(byteBuf); ByteBuf duplicate = buff.getByteBuf(); duplicate.writerIndex(5); assertEquals(11, byteBuf.writerIndex()); @@ -1199,7 +1200,7 @@ private void checkGetXXXUpperBound(BiFunction f, int siz public void testReadOnlyByteBuf() { String s = "Hello World"; ByteBuf byteBuf = Unpooled.buffer(0, s.length() - 1); - Buffer buff = Buffer.buffer(byteBuf.asReadOnly()); + Buffer buff = BufferInternal.buffer(byteBuf.asReadOnly()); assertSame(buff, buff.copy()); } } diff --git a/src/test/java/io/vertx/core/datagram/DatagramTest.java b/src/test/java/io/vertx/core/datagram/DatagramTest.java index 1ac973f049c..19bdd2903e5 100644 --- a/src/test/java/io/vertx/core/datagram/DatagramTest.java +++ b/src/test/java/io/vertx/core/datagram/DatagramTest.java @@ -20,6 +20,7 @@ import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.impl.Utils; import io.vertx.core.json.JsonObject; import io.vertx.core.net.NetworkOptions; @@ -103,7 +104,7 @@ public void testSendReceive() throws Exception { assertSame(serverContext, Vertx.currentContext()); assertFalse(Thread.holdsLock(peer2)); Buffer data = packet.data(); - ByteBuf buff = data.getByteBuf(); + ByteBuf buff = ((BufferInternal)data).getByteBuf(); while (buff != buff.unwrap() && buff.unwrap() != null) { buff = buff.unwrap(); } diff --git a/src/test/java/io/vertx/core/dns/HostnameResolutionTest.java b/src/test/java/io/vertx/core/dns/HostnameResolutionTest.java index 87c641a3bb7..bca66fecdf3 100644 --- a/src/test/java/io/vertx/core/dns/HostnameResolutionTest.java +++ b/src/test/java/io/vertx/core/dns/HostnameResolutionTest.java @@ -327,7 +327,7 @@ public void testAsyncResolveConnectIsNotifiedOnChannelEventLoop() throws Excepti CountDownLatch connectLatch = new CountDownLatch(1); Bootstrap bootstrap = new Bootstrap(); bootstrap.channelFactory(((VertxInternal)vertx).transport().channelFactory(false)); - bootstrap.group(vertx.nettyEventLoopGroup()); + bootstrap.group(((VertxInternal)vertx).nettyEventLoopGroup()); bootstrap.resolver(((VertxInternal) vertx).nettyAddressResolverGroup()); bootstrap.handler(new ChannelInitializer() { @Override diff --git a/src/test/java/io/vertx/core/file/FileSystemTest.java b/src/test/java/io/vertx/core/file/FileSystemTest.java index 1a5402fdfad..3fa0435933f 100644 --- a/src/test/java/io/vertx/core/file/FileSystemTest.java +++ b/src/test/java/io/vertx/core/file/FileSystemTest.java @@ -15,6 +15,7 @@ import io.netty.buffer.Unpooled; import io.vertx.core.*; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.file.impl.AsyncFileImpl; import io.vertx.core.impl.Utils; import io.vertx.core.json.JsonObject; @@ -1228,7 +1229,7 @@ public void testWriteStreamWithCompositeBuffer() { byte[] content1 = TestUtils.randomByteArray(chunkSize * (chunks / 2)); byte[] content2 = TestUtils.randomByteArray(chunkSize * (chunks / 2)); ByteBuf byteBuf = Unpooled.wrappedBuffer(content1, content2); - Buffer buff = Buffer.buffer(byteBuf); + Buffer buff = BufferInternal.buffer(byteBuf); vertx.fileSystem().open(testDir + pathSep + fileName, new OpenOptions()).onComplete(onSuccess(ws -> { ws.exceptionHandler(t -> fail(t.getMessage())); ws.write(buff); diff --git a/src/test/java/io/vertx/core/http/Http2ClientTest.java b/src/test/java/io/vertx/core/http/Http2ClientTest.java index 4139ebcc7f5..932d3534d8c 100644 --- a/src/test/java/io/vertx/core/http/Http2ClientTest.java +++ b/src/test/java/io/vertx/core/http/Http2ClientTest.java @@ -35,6 +35,7 @@ import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.impl.Http2UpgradeClientConnection; import io.vertx.core.http.impl.HttpClientConnection; import io.vertx.core.net.NetServer; @@ -1226,7 +1227,7 @@ public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers // ChannelFuture a = encoder.frameWriter().writeData(request.context, id, Buffer.buffer("hello").getByteBuf(), 12, false, request.context.newPromise()); // normal frame : 00 00 12 00 08 00 00 00 03 0c 68 65 6c 6c 6f 00 00 00 00 00 00 00 00 00 00 00 00 // corrupted frame : 00 00 12 00 08 00 00 00 03 1F 68 65 6c 6c 6f 00 00 00 00 00 00 00 00 00 00 00 00 - ctx.channel().write(Buffer.buffer(new byte[]{ + ctx.channel().write(BufferInternal.buffer(new byte[]{ 0x00, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, (byte)(streamId & 0xFF), 0x1F, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }).getByteBuf()); @@ -2115,7 +2116,7 @@ public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int ctx.flush(); encoder.writePriority(ctx, streamId, responseStreamPriority2.getDependency(), responseStreamPriority2.getWeight(), responseStreamPriority2.isExclusive(), ctx.newPromise()); ctx.flush(); - encoder.writeData(ctx, streamId, Buffer.buffer("hello").getByteBuf(), 0, true, ctx.newPromise()); + encoder.writeData(ctx, streamId, BufferInternal.buffer("hello").getByteBuf(), 0, true, ctx.newPromise()); ctx.flush(); vertx.runOnContext(v -> { complete(); @@ -2228,7 +2229,7 @@ public void testServerStreamPriorityNoChange() throws Exception { public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int streamDependency, short weight, boolean exclusive, int padding, boolean endStream) throws Http2Exception { encoder.writeHeaders(ctx, streamId, new DefaultHttp2Headers().status("200"), streamPriority.getDependency(), streamPriority.getWeight(), streamPriority.isExclusive(), 0, false, ctx.newPromise()); encoder.writePriority(ctx, streamId, streamPriority.getDependency(), streamPriority.getWeight(), streamPriority.isExclusive(), ctx.newPromise()); - encoder.writeData(ctx, streamId, Buffer.buffer("hello").getByteBuf(), 0, true, ctx.newPromise()); + encoder.writeData(ctx, streamId, BufferInternal.buffer("hello").getByteBuf(), 0, true, ctx.newPromise()); ctx.flush(); } @Override diff --git a/src/test/java/io/vertx/core/http/Http2ServerTest.java b/src/test/java/io/vertx/core/http/Http2ServerTest.java index 71ec88e5c02..9f17a551838 100644 --- a/src/test/java/io/vertx/core/http/Http2ServerTest.java +++ b/src/test/java/io/vertx/core/http/Http2ServerTest.java @@ -56,6 +56,7 @@ import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.impl.Http1xOrH2CHandler; import io.vertx.core.http.impl.HttpUtils; import io.vertx.core.impl.Utils; @@ -635,7 +636,7 @@ public void testPost() throws Exception { ChannelFuture fut = client.connect(DEFAULT_HTTPS_PORT, DEFAULT_HTTPS_HOST, request -> { int id = request.nextStreamId(); request.encoder.writeHeaders(request.context, id, POST("/").set("content-type", "text/plain"), 0, false, request.context.newPromise()); - request.encoder.writeData(request.context, id, expectedContent.getByteBuf(), 0, true, request.context.newPromise()); + request.encoder.writeData(request.context, id, ((BufferInternal)expectedContent).getByteBuf(), 0, true, request.context.newPromise()); request.context.flush(); }); fut.sync(); @@ -681,7 +682,7 @@ public void testPostFileUpload() throws Exception { int id = request.nextStreamId(); request.encoder.writeHeaders(request.context, id, POST("/form"). set("content-type", contentType).set("content-length", contentLength), 0, false, request.context.newPromise()); - request.encoder.writeData(request.context, id, Buffer.buffer(body).getByteBuf(), 0, true, request.context.newPromise()); + request.encoder.writeData(request.context, id, BufferInternal.buffer(body).getByteBuf(), 0, true, request.context.newPromise()); request.context.flush(); }); fut.sync(); @@ -759,7 +760,7 @@ void send() { if (writable) { Buffer buf = Buffer.buffer(chunk); expected.appendBuffer(buf); - request.encoder.writeData(request.context, id, buf.getByteBuf(), 0, false, request.context.newPromise()); + request.encoder.writeData(request.context, id, ((BufferInternal)buf).getByteBuf(), 0, false, request.context.newPromise()); request.context.flush(); request.context.executor().execute(this::send); } else { @@ -970,7 +971,7 @@ public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorC }); Http2ConnectionEncoder encoder = request.encoder; encoder.writeHeaders(request.context, id, GET("/"), 0, false, request.context.newPromise()); - encoder.writeData(request.context, id, Buffer.buffer("hello").getByteBuf(), 0, end, request.context.newPromise()); + encoder.writeData(request.context, id, BufferInternal.buffer("hello").getByteBuf(), 0, end, request.context.newPromise()); }); fut.sync(); @@ -1010,7 +1011,7 @@ public void testClientResetServerStream() throws Exception { int id = request.nextStreamId(); Http2ConnectionEncoder encoder = request.encoder; encoder.writeHeaders(request.context, id, GET("/"), 0, false, request.context.newPromise()); - encoder.writeData(request.context, id, Buffer.buffer("hello").getByteBuf(), 0, false, request.context.newPromise()); + encoder.writeData(request.context, id, BufferInternal.buffer("hello").getByteBuf(), 0, false, request.context.newPromise()); bufReceived.future().onComplete(ar -> { encoder.writeRstStream(request.context, id, 10, request.context.newPromise()); request.context.flush(); @@ -1391,7 +1392,7 @@ private void testHandlerFailure(boolean data, BiConsumer { int id = request.nextStreamId(); request.encoder.writeHeaders(request.context, id, POST("/").add("content-encoding", "gzip"), 0, false, request.context.newPromise()); - request.encoder.writeData(request.context, id, Buffer.buffer(expectedGzipped).getByteBuf(), 0, true, request.context.newPromise()); + request.encoder.writeData(request.context, id, BufferInternal.buffer(expectedGzipped).getByteBuf(), 0, true, request.context.newPromise()); request.context.flush(); }); fut.sync(); @@ -2202,7 +2203,7 @@ public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers vertx.runOnContext(v -> { assertEquals("100", headers.status().toString()); }); - request.encoder.writeData(request.context, id, Buffer.buffer("the-body").getByteBuf(), 0, true, request.context.newPromise()); + request.encoder.writeData(request.context, id, BufferInternal.buffer("the-body").getByteBuf(), 0, true, request.context.newPromise()); request.context.flush(); break; case 1: @@ -2305,7 +2306,7 @@ public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers assertEquals("200", headers.status().toString()); assertFalse(endStream); }); - request.encoder.writeData(request.context, id, Buffer.buffer("some-data").getByteBuf(), 0, false, request.context.newPromise()); + request.encoder.writeData(request.context, id, BufferInternal.buffer("some-data").getByteBuf(), 0, false, request.context.newPromise()); request.context.flush(); } StringBuilder received = new StringBuilder(); @@ -2318,7 +2319,7 @@ public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int vertx.runOnContext(v -> { assertFalse(endOfStream); }); - request.encoder.writeData(request.context, id, Buffer.buffer("last-data").getByteBuf(), 0, true, request.context.newPromise()); + request.encoder.writeData(request.context, id, BufferInternal.buffer("last-data").getByteBuf(), 0, true, request.context.newPromise()); } else if (endOfStream) { vertx.runOnContext(v -> { assertEquals("last-data", received.toString()); @@ -2440,7 +2441,7 @@ public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers vertx.runOnContext(v -> { assertEquals(0, c); }); - request.encoder.writeData(request.context, id, Buffer.buffer("some-data").getByteBuf(), 0, false, request.context.newPromise()); + request.encoder.writeData(request.context, id, BufferInternal.buffer("some-data").getByteBuf(), 0, false, request.context.newPromise()); request.context.flush(); } StringBuilder received = new StringBuilder(); @@ -2449,7 +2450,7 @@ public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int String s = data.toString(StandardCharsets.UTF_8); received.append(s); if (endOfStream) { - request.encoder.writeData(request.context, id, Buffer.buffer("last-data").getByteBuf(), 0, true, request.context.newPromise()); + request.encoder.writeData(request.context, id, BufferInternal.buffer("last-data").getByteBuf(), 0, true, request.context.newPromise()); vertx.runOnContext(v -> { assertEquals("some-data", received.toString()); complete(); @@ -2574,7 +2575,7 @@ public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int } }); request.encoder.writeHeaders(request.context, id, GET("/"), 0, false, request.context.newPromise()); - request.encoder.writeFrame(request.context, (byte)10, id, new Http2Flags((short) 253), expectedSend.getByteBuf(), request.context.newPromise()); + request.encoder.writeFrame(request.context, (byte)10, id, new Http2Flags((short) 253), ((BufferInternal)expectedSend).getByteBuf(), request.context.newPromise()); request.context.flush(); }); fut.sync(); @@ -3202,7 +3203,7 @@ public void testStreamPriorityChange() throws Exception { request.context.flush(); request.encoder.writePriority(request.context, id, requestStreamPriority2.getDependency(), requestStreamPriority2.getWeight(), requestStreamPriority2.isExclusive(), request.context.newPromise()); request.context.flush(); - request.encoder.writeData(request.context, id, Buffer.buffer("hello").getByteBuf(), 0, true, request.context.newPromise()); + request.encoder.writeData(request.context, id, BufferInternal.buffer("hello").getByteBuf(), 0, true, request.context.newPromise()); request.context.flush(); request.decoder.frameListener(new Http2FrameAdapter() { @Override @@ -3285,7 +3286,7 @@ public void testStreamPriorityNoChange() throws Exception { request.context.flush(); request.encoder.writePriority(request.context, id, requestStreamPriority.getDependency(), requestStreamPriority.getWeight(), requestStreamPriority.isExclusive(), request.context.newPromise()); request.context.flush(); - request.encoder.writeData(request.context, id, Buffer.buffer("hello").getByteBuf(), 0, true, request.context.newPromise()); + request.encoder.writeData(request.context, id, BufferInternal.buffer("hello").getByteBuf(), 0, true, request.context.newPromise()); request.context.flush(); request.decoder.frameListener(new Http2FrameAdapter() { @Override diff --git a/src/test/java/io/vertx/core/http/HttpBandwidthLimitingTest.java b/src/test/java/io/vertx/core/http/HttpBandwidthLimitingTest.java index 788298c255f..6fc0fb9749b 100644 --- a/src/test/java/io/vertx/core/http/HttpBandwidthLimitingTest.java +++ b/src/test/java/io/vertx/core/http/HttpBandwidthLimitingTest.java @@ -258,7 +258,7 @@ public Handler getFile(File expected) { public Handler bufferWrite(Buffer expected) { return req -> { req.bodyHandler(buffer -> { - assertEquals(expected.getByteBuf(), buffer.getByteBuf()); + assertEquals(expected, buffer); testComplete(); }); }; diff --git a/src/test/java/io/vertx/core/http/HttpCompressionTestBase.java b/src/test/java/io/vertx/core/http/HttpCompressionTestBase.java index 116874bac9e..b402db898cf 100644 --- a/src/test/java/io/vertx/core/http/HttpCompressionTestBase.java +++ b/src/test/java/io/vertx/core/http/HttpCompressionTestBase.java @@ -18,6 +18,7 @@ import io.netty.util.CharsetUtil; import io.netty.util.internal.StringUtil; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import org.junit.Test; import java.util.Queue; @@ -59,7 +60,7 @@ protected void configureServerCompression(HttpServerOptions options) { protected Buffer compress(Buffer src) { EmbeddedChannel channel = new EmbeddedChannel(); channel.pipeline().addFirst(encoder()); - channel.writeAndFlush(Unpooled.copiedBuffer(src.getByteBuf())); + channel.writeAndFlush(Unpooled.copiedBuffer(((BufferInternal)src).getByteBuf())); channel.close(); Queue messages = channel.outboundMessages(); Buffer dst = Buffer.buffer(); diff --git a/src/test/java/io/vertx/core/http/WebSocketTest.java b/src/test/java/io/vertx/core/http/WebSocketTest.java index 666da6be432..59ca8f7f82d 100644 --- a/src/test/java/io/vertx/core/http/WebSocketTest.java +++ b/src/test/java/io/vertx/core/http/WebSocketTest.java @@ -29,6 +29,7 @@ import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.impl.Http1xClientConnection; import io.vertx.core.http.impl.Http1xServerConnection; import io.vertx.core.http.impl.WebSocketInternal; @@ -2519,8 +2520,8 @@ public void testServerWebSocketReceivePongExceedsMaxFrameSize() throws Interrupt client = vertx.createHttpClient(); client.webSocket(DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, "/").onComplete(onSuccess(ws -> { try { - ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PONG, ping1.copy().getByteBuf(), false)); - ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PONG, ping2.copy().getByteBuf(), true)); + ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PONG, ((BufferInternal)ping1.copy()).getByteBuf(), false)); + ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PONG, ((BufferInternal)ping2.copy()).getByteBuf(), true)); } catch(Throwable t) { fail(t); } @@ -2538,8 +2539,8 @@ public void testClientWebSocketReceivePongExceedsMaxFrameSize() throws Interrupt server = vertx.createHttpServer(new HttpServerOptions().setIdleTimeout(1).setPort(DEFAULT_HTTP_PORT).setHost(HttpTestBase.DEFAULT_HTTP_HOST).setMaxWebSocketFrameSize(maxFrameSize)); server.webSocketHandler(ws -> { try { - ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PONG, ping1.copy().getByteBuf(), false)); - ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PONG, ping2.copy().getByteBuf(), true)); + ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PONG, ((BufferInternal)ping1.copy()).getByteBuf(), false)); + ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PONG, ((BufferInternal)ping2.copy()).getByteBuf(), true)); } catch(Throwable t) { fail(t); } @@ -2585,8 +2586,8 @@ public void testServerWebSocketReceivePingExceedsMaxFrameSize() throws Interrupt } }); try { - ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PING, ping1.copy().getByteBuf(), false)); - ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PING, ping2.copy().getByteBuf(), true)); + ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PING, ((BufferInternal)ping1.copy()).getByteBuf(), false)); + ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PING, ((BufferInternal)ping2.copy()).getByteBuf(), true)); } catch(Throwable t) { fail(t); } @@ -2619,8 +2620,8 @@ public void testClientWebSocketReceivePingExceedsMaxFrameSize() throws Interrupt } }); try { - ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PING, ping1.copy().getByteBuf(), false)); - ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PING, ping2.copy().getByteBuf(), true)); + ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PING, ((BufferInternal)ping1.copy()).getByteBuf(), false)); + ws.writeFrame(new WebSocketFrameImpl(WebSocketFrameType.PING, ((BufferInternal)ping2.copy()).getByteBuf(), true)); } catch(Throwable t) { fail(t); } @@ -2699,7 +2700,7 @@ private void testCloseStatusCodeFromServer(Consumer closeOp) th vertx.runOnContext(v -> { client.webSocket(DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, "/").onComplete(onSuccess(ws -> { ws.frameHandler(frame -> { - assertEquals(1000, frame.binaryData().getByteBuf().getShort(0)); + assertEquals(1000, ((BufferInternal)frame.binaryData()).getByteBuf().getShort(0)); assertEquals(1000, frame.closeStatusCode()); assertNull(frame.closeReason()); complete(); @@ -2723,7 +2724,7 @@ public void testCloseStatusCodeFromClient() throws InterruptedException { latch.countDown(); }); socket.frameHandler(frame -> { - assertEquals(1000, frame.binaryData().getByteBuf().getShort(0)); + assertEquals(1000, ((BufferInternal)frame.binaryData()).getByteBuf().getShort(0)); assertEquals(1000, frame.closeStatusCode()); assertNull(frame.closeReason()); latch.countDown(); @@ -2791,8 +2792,8 @@ private void testCloseCustomPayloadFromServer(Consumer closeOp) vertx.runOnContext(v -> { client.webSocket(DEFAULT_HTTP_PORT, HttpTestBase.DEFAULT_HTTP_HOST, "/").onComplete(onSuccess(ws -> { ws.frameHandler(frame -> { - assertEquals(TEST_REASON, frame.binaryData().getByteBuf().readerIndex(2).toString(StandardCharsets.UTF_8)); - assertEquals(TEST_STATUS_CODE, frame.binaryData().getByteBuf().getShort(0)); + assertEquals(TEST_REASON, ((BufferInternal)frame.binaryData()).getByteBuf().readerIndex(2).toString(StandardCharsets.UTF_8)); + assertEquals(TEST_STATUS_CODE, ((BufferInternal)frame.binaryData()).getByteBuf().getShort(0)); assertEquals(TEST_REASON, frame.closeReason()); assertEquals(TEST_STATUS_CODE, frame.closeStatusCode()); complete(); @@ -2822,8 +2823,8 @@ private void testCloseCustomPayloadFromClient(Consumer closeOp) throw complete(); }); socket.frameHandler(frame -> { - assertEquals(TEST_REASON, frame.binaryData().getByteBuf().readerIndex(2).toString(StandardCharsets.UTF_8)); - assertEquals(TEST_STATUS_CODE, frame.binaryData().getByteBuf().getShort(0)); + assertEquals(TEST_REASON, ((BufferInternal)frame.binaryData()).getByteBuf().readerIndex(2).toString(StandardCharsets.UTF_8)); + assertEquals(TEST_STATUS_CODE, ((BufferInternal)frame.binaryData()).getByteBuf().getShort(0)); assertEquals(TEST_REASON, frame.closeReason()); assertEquals(TEST_STATUS_CODE, frame.closeStatusCode()); complete(); diff --git a/src/test/java/io/vertx/core/net/NetTest.java b/src/test/java/io/vertx/core/net/NetTest.java index c0eccacd6ef..4ded4e0e3b2 100755 --- a/src/test/java/io/vertx/core/net/NetTest.java +++ b/src/test/java/io/vertx/core/net/NetTest.java @@ -44,6 +44,7 @@ import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.eventbus.Message; import io.vertx.core.eventbus.MessageConsumer; import io.vertx.core.http.*; @@ -3478,7 +3479,7 @@ public void testNetSocketInternalBuffer() throws Exception { server.connectHandler(so -> { NetSocketInternal soi = (NetSocketInternal) so; soi.handler(msg -> { - ByteBuf byteBuf = msg.getByteBuf(); + ByteBuf byteBuf = ((BufferInternal)msg).getByteBuf(); assertFalse(byteBuf.isDirect()); assertEquals(1, byteBuf.refCnt()); assertFalse(byteBuf.release()); @@ -3491,7 +3492,7 @@ public void testNetSocketInternalBuffer() throws Exception { NetSocketInternal soi = (NetSocketInternal) so; soi.write(Buffer.buffer("Hello World")); soi.handler(msg -> { - ByteBuf byteBuf = msg.getByteBuf(); + ByteBuf byteBuf = ((BufferInternal)msg).getByteBuf(); assertFalse(byteBuf.isDirect()); assertEquals(1, byteBuf.refCnt()); assertFalse(byteBuf.release()); diff --git a/src/test/java/io/vertx/core/spi/metrics/MetricsTest.java b/src/test/java/io/vertx/core/spi/metrics/MetricsTest.java index 0fe75a53df9..fb10aa77512 100644 --- a/src/test/java/io/vertx/core/spi/metrics/MetricsTest.java +++ b/src/test/java/io/vertx/core/spi/metrics/MetricsTest.java @@ -1151,7 +1151,7 @@ public void testInitialization() { assertSame(vertx, ((FakeVertxMetrics)FakeMetricsBase.getMetrics(vertx)).vertx()); startNodes(1); assertSame(vertices[0], ((FakeVertxMetrics)FakeMetricsBase.getMetrics(vertices[0])).vertx()); - EventLoopGroup group = vertx.nettyEventLoopGroup(); + EventLoopGroup group = ((VertxInternal)vertx).nettyEventLoopGroup(); Set loops = new HashSet<>(); int count = 0; while (true) { diff --git a/src/test/java/io/vertx/test/core/TestUtils.java b/src/test/java/io/vertx/test/core/TestUtils.java index 6700d1ca8ad..7b3e9263fd9 100644 --- a/src/test/java/io/vertx/test/core/TestUtils.java +++ b/src/test/java/io/vertx/test/core/TestUtils.java @@ -41,6 +41,7 @@ import io.vertx.core.Future; import io.vertx.core.MultiMap; import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.BufferInternal; import io.vertx.core.http.Http2Settings; import io.vertx.core.net.JksOptions; import io.vertx.core.net.KeyCertOptions; @@ -450,10 +451,10 @@ public static TrustOptions randomTrustOptions() { } public static Buffer leftPad(int padding, Buffer buffer) { - return Buffer.buffer(Unpooled.buffer() + return BufferInternal.buffer(Unpooled.buffer() .writerIndex(padding) .readerIndex(padding) - .writeBytes(buffer.getByteBuf()) + .writeBytes(((BufferInternal)buffer).getByteBuf()) ); } From 0ab22102d6d6f265e3a9caecbcaad482af9bdad7 Mon Sep 17 00:00:00 2001 From: Thomas Segismont Date: Thu, 6 Jul 2023 18:46:06 +0200 Subject: [PATCH 029/264] Remove CLI and Launcher from the docs Signed-off-by: Thomas Segismont --- src/main/asciidoc/cli-for-java.adoc | 81 --- src/main/asciidoc/cli.adoc | 180 ----- src/main/asciidoc/eventbus.adoc | 19 +- src/main/asciidoc/http.adoc | 15 +- src/main/asciidoc/index.adoc | 616 ------------------ src/main/asciidoc/net.adoc | 8 - .../override/configuring-eventbus.adoc | 6 +- src/main/java/examples/cli/AnnotatedCli.java | 45 -- src/main/java/examples/cli/CLIExamples.java | 155 ----- src/main/java/examples/cli/MyCommand.java | 39 -- .../java/examples/cli/TypedCLIExamples.java | 87 --- src/main/java/examples/cli/package-info.java | 18 - 12 files changed, 16 insertions(+), 1253 deletions(-) delete mode 100644 src/main/asciidoc/cli-for-java.adoc delete mode 100644 src/main/asciidoc/cli.adoc delete mode 100644 src/main/java/examples/cli/AnnotatedCli.java delete mode 100644 src/main/java/examples/cli/CLIExamples.java delete mode 100644 src/main/java/examples/cli/MyCommand.java delete mode 100644 src/main/java/examples/cli/TypedCLIExamples.java delete mode 100644 src/main/java/examples/cli/package-info.java diff --git a/src/main/asciidoc/cli-for-java.adoc b/src/main/asciidoc/cli-for-java.adoc deleted file mode 100644 index 8d3f8811423..00000000000 --- a/src/main/asciidoc/cli-for-java.adoc +++ /dev/null @@ -1,81 +0,0 @@ -=== Typed options and arguments - -The described {@link io.vertx.core.cli.Option} and {@link io.vertx.core.cli.Argument} classes are _untyped_, -meaning that the only get String values. -{@link io.vertx.core.cli.TypedOption} and {@link io.vertx.core.cli.TypedArgument} let you specify a _type_, so the -(String) raw value is converted to the specified type. - -Instead of -{@link io.vertx.core.cli.Option} and {@link io.vertx.core.cli.Argument}, use {@link io.vertx.core.cli.TypedOption} -and {@link io.vertx.core.cli.TypedArgument} in the {@link io.vertx.core.cli.CLI} definition: - -[source,java] ----- -{@link examples.cli.TypedCLIExamples#example1} ----- - -Then you can retrieve the converted values as follows: - -[source,java] ----- -{@link examples.cli.TypedCLIExamples#example2} ----- - -The vert.x CLI is able to convert to classes: - -* having a constructor with a single -{@link java.lang.String} argument, such as {@link java.io.File} or {@link io.vertx.core.json.JsonObject} -* with a static `from` or `fromString` method -* with a static `valueOf` method, such as primitive types and enumeration - -In addition, you can implement your own {@link io.vertx.core.cli.converters.Converter} and instruct the CLI to use -this converter: - -[source,java] ----- -{@link examples.cli.TypedCLIExamples#example3} ----- - -For booleans, the boolean values are evaluated to `true`: `on`, `yes`, `1`, `true`. - -If one of your option has an `enum` as type, it computes the set of choices automatically. - -=== Using annotations - -You can also define your CLI using annotations. Definition is done using annotation on the class and on _setter_ -methods: - -[source, java] ----- -@Name("some-name") -@Summary("some short summary.") -@Description("some long description") -public class AnnotatedCli { - - private boolean flag; - private String name; - private String arg; - - @Option(shortName = "f", flag = true) - public void setFlag(boolean flag) { - this.flag = flag; - } - - @Option(longName = "name") - public void setName(String name) { - this.name = name; - } - - @Argument(index = 0) - public void setArg(String arg) { - this.arg = arg; - } -} ----- - -Once annotated, you can define the {@link io.vertx.core.cli.CLI} and inject the values using: - -[source,java] ----- -{@link examples.cli.TypedCLIExamples#example4} ----- diff --git a/src/main/asciidoc/cli.adoc b/src/main/asciidoc/cli.adoc deleted file mode 100644 index c2036876423..00000000000 --- a/src/main/asciidoc/cli.adoc +++ /dev/null @@ -1,180 +0,0 @@ -Vert.x Core provides an API for parsing command line arguments passed to programs. It's also able to print help -messages detailing the options available for a command line tool. Even if such features are far from -the Vert.x core topics, this API is used in the {@link io.vertx.core.Launcher} class that you can use in _fat-jar_ -and in the `vertx` command line tools. In addition, it's polyglot (can be used from any supported language) and is -used in Vert.x Shell. - -Vert.x CLI provides a model to describe your command line interface, but also a parser. This parser supports -different types of syntax: - -* POSIX like options (ie. `tar -zxvf foo.tar.gz`) -* GNU like long options (ie. `du --human-readable --max-depth=1`) -* Java like properties (ie. `java -Djava.awt.headless=true -Djava.net.useSystemProxies=true Foo`) -* Short options with value attached (ie. `gcc -O2 foo.c`) -* Long options with single hyphen (ie. `ant -projecthelp`) - -Using the CLI api is a 3-steps process: - -1. The definition of the command line interface -2. The parsing of the user command line -3. The query / interrogation - -=== Definition Stage - -Each command line interface must define the set of options and arguments that will be used. It also requires a -name. The CLI API uses the {@link io.vertx.core.cli.Option} and {@link io.vertx.core.cli.Argument} classes to -describe options and arguments: - -[source,$lang] ----- -{@link examples.cli.CLIExamples#example1} ----- - -As you can see, you can create a new {@link io.vertx.core.cli.CLI} using -{@link io.vertx.core.cli.CLI#create(java.lang.String)}. The passed string is the name of the CLI. Once created you -can set the summary and description. The summary is intended to be short (one line), while the description can -contain more details. Each option and argument are also added on the `CLI` object using the -{@link io.vertx.core.cli.CLI#addArgument(io.vertx.core.cli.Argument)} and -{@link io.vertx.core.cli.CLI#addOption(io.vertx.core.cli.Option)} methods. - -==== Options - -An {@link io.vertx.core.cli.Option} is a command line parameter identified by a _key_ present in the user command -line. Options must have at least a long name or a short name. Long name are generally used using a `--` prefix, -while short names are used with a single `-`. Names are case-sensitive; however, case-insensitive name matching -will be used during the <> if no exact match is found. -Options can get a description displayed in the usage (see below). Options can receive 0, 1 or several values. An -option receiving 0 values is a `flag`, and must be declared using -{@link io.vertx.core.cli.Option#setFlag(boolean)}. By default, options receive a single value, however, you can -configure the option to receive several values using {@link io.vertx.core.cli.Option#setMultiValued(boolean)}: - -[source,$lang] ----- -{@link examples.cli.CLIExamples#example2} ----- - -Options can be marked as mandatory. A mandatory option not set in the user command line throws an exception during -the parsing: - -[source,$lang] ----- -{@link examples.cli.CLIExamples#example3} ----- - -Non-mandatory options can have a _default value_. This value would be used if the user does not set the option in -the command line: - -[source,$lang] ----- -{@link examples.cli.CLIExamples#example4} ----- - -An option can be _hidden_ using the {@link io.vertx.core.cli.Option#setHidden(boolean)} method. Hidden option are -not listed in the usage, but can still be used in the user command line (for power-users). - -If the option value is constrained to a fixed set, you can set the different acceptable choices: - -[source,$lang] ----- -{@link examples.cli.CLIExamples#example41} ----- - -Options can also be instantiated from their JSON form. - -==== Arguments - -Unlike options, arguments do not have a _key_ and are identified by their _index_. For example, in -`java com.acme.Foo`, `com.acme.Foo` is an argument. - -Arguments do not have a name, there are identified using a 0-based index. The first parameter has the -index `0`: - -[source,$lang] ----- -{@link examples.cli.CLIExamples#example5} ----- - -If you don't set the argument indexes, it computes it automatically by using the declaration order. - -[source,$lang] ----- -{@link examples.cli.CLIExamples#example51} ----- - -The `argName` is optional and used in the usage message. - -As options, {@link io.vertx.core.cli.Argument} can: - -* be hidden using {@link io.vertx.core.cli.Argument#setHidden(boolean)} -* be mandatory using {@link io.vertx.core.cli.Argument#setRequired(boolean)} -* have a default value using {@link io.vertx.core.cli.Argument#setDefaultValue(java.lang.String)} -* receive several values using {@link io.vertx.core.cli.Argument#setMultiValued(boolean)} - only the last argument -can be multi-valued. - -Arguments can also be instantiated from their JSON form. - -==== Usage generation - -Once your {@link io.vertx.core.cli.CLI} instance is configured, you can generate the _usage_ message: - -[source,$lang] ----- -{@link examples.cli.CLIExamples#example6} ----- - -It generates a usage message like this one: - -[source] ----- -Usage: copy [-R] source target - -A command line interface to copy files. - - -R,--directory enables directory support ----- - -If you need to tune the usage message, check the {@link io.vertx.core.cli.UsageMessageFormatter} class. - -=== Parsing Stage - -Once your {@link io.vertx.core.cli.CLI} instance is configured, you can parse the user command line to evaluate -each option and argument: - -[source,$lang] ----- -{@link examples.cli.CLIExamples#example7} ----- - -The {@link io.vertx.core.cli.CLI#parse(java.util.List)} method returns a {@link io.vertx.core.cli.CommandLine} -object containing the values. By default, it validates the user command line and checks that each mandatory options -and arguments have been set as well as the number of values received by each option. You can disable the -validation by passing `false` as second parameter of {@link io.vertx.core.cli.CLI#parse(java.util.List,boolean)}. -This is useful if you want to check an argument or option is present even if the parsed command line is invalid. - -You can check whether or not the -{@link io.vertx.core.cli.CommandLine} is valid using {@link io.vertx.core.cli.CommandLine#isValid()}. - -[[query_interrogation_stage]] -=== Query / Interrogation Stage - -Once parsed, you can retrieve the values of the options and arguments from the -{@link io.vertx.core.cli.CommandLine} object returned by the {@link io.vertx.core.cli.CLI#parse(java.util.List)} -method: - -[source,$lang] ----- -{@link examples.cli.CLIExamples#example8} ----- - -One of your options can be marked as "help". If a user command line enabled a "help" option, the validation -won't fail, but you have the opportunity to check if the user asks for help: - -[source,$lang] ----- -{@link examples.cli.CLIExamples#example9} ----- - -[language,java] ----- -include::cli-for-java.adoc[] ----- diff --git a/src/main/asciidoc/eventbus.adoc b/src/main/asciidoc/eventbus.adoc index c94ab27b483..4702504e1df 100644 --- a/src/main/asciidoc/eventbus.adoc +++ b/src/main/asciidoc/eventbus.adoc @@ -253,28 +253,17 @@ include::override/eventbus.adoc[] ==== Clustered Event Bus -The event bus doesn't just exist in a single Vert.x instance. By clustering different Vert.x instances together on -your network they can form a single, distributed event bus. +The event bus doesn't just exist in a single Vert.x instance. +By clustering different Vert.x instances together on your network they can form a single, distributed event bus. -==== Clustering programmatically - -If you're creating your Vert.x instance programmatically you get a clustered event bus by configuring the Vert.x -instance as clustered; +If you're creating your Vert.x instance programmatically, you get a clustered event bus by configuring the Vert.x instance as clustered: [source,$lang] ---- {@link examples.EventBusExamples#example12} ---- -You should also make sure you have a {@link io.vertx.core.spi.cluster.ClusterManager} implementation on your classpath, for example the Hazelcast cluster manager. - -==== Clustering on the command line - -You can run Vert.x clustered on the command line with - ----- -vertx run my-verticle.js -cluster ----- +You should also make sure you have one of the link:/docs/#clustering[{@link io.vertx.core.spi.cluster.ClusterManager} implementations] on your classpath. === Automatic clean-up in verticles diff --git a/src/main/asciidoc/http.adoc b/src/main/asciidoc/http.adoc index 52d47065a45..1778cea4209 100644 --- a/src/main/asciidoc/http.adoc +++ b/src/main/asciidoc/http.adoc @@ -1668,14 +1668,17 @@ Let's take a verticle creating a HTTP server such as: {@link examples.HTTPExamples#serversharing(io.vertx.core.Vertx)} ---- -This service is listening on the port 8080. So, when this verticle is instantiated multiple times as with: -`vertx run io.vertx.examples.http.sharing.HttpServerVerticle -instances 2`, what's happening ? If both -verticles would bind to the same port, you would receive a socket exception. Fortunately, vert.x is handling -this case for you. When you deploy another server on the same host and port as an existing server it doesn't -actually try and create a new server listening on the same host/port. It binds only once to the socket. When -receiving a request it calls the server handlers following a round robin strategy. +This service is listening on the port 8080. + +So, when this verticle is instantiated multiple times as with: `deploymentOptions.setInstances(2)`, what's happening ? +If both verticles bound to the same port, you would receive a socket exception. +Fortunately, vert.x is handling this case for you. +When you deploy another server on the same host and port as an existing server it doesn't actually try and create a new server listening on the same host/port. +It binds only once to the socket. +When receiving a request it calls the server handlers following a round-robin strategy. Let's now imagine a client such as: + [source,$lang] ---- {@link examples.HTTPExamples#serversharingclient(io.vertx.core.Vertx)} diff --git a/src/main/asciidoc/index.adoc b/src/main/asciidoc/index.adoc index 82d4241870e..f56be1d84e8 100644 --- a/src/main/asciidoc/index.adoc +++ b/src/main/asciidoc/index.adoc @@ -370,63 +370,6 @@ and multiple cores on your machine, so you want to deploy multiple instances to include::override/verticle-configuration.adoc[] -=== High Availability - -Verticles can be deployed with High Availability (HA) enabled. In that context, when a verticle is deployed on -a vert.x instance that dies abruptly, the verticle is redeployed on another vert.x instance from the cluster. - -To run an verticle with the high availability enabled, just append the `-ha` switch: - -[source] ----- -vertx run my-verticle.js -ha ----- - -When enabling high availability, no need to add `-cluster`. - -More details about the high availability feature and configuration in the <> - section. - - -=== Running Verticles from the command line - -You can use Vert.x directly in your Maven or Gradle projects in the normal way by adding a dependency to the Vert.x -core library and hacking from there. - -However you can also run Vert.x verticles directly from the command line if you wish. - -To do this you need to download and install a Vert.x distribution, and add the `bin` directory of the installation -to your `PATH` environment variable. Also make sure you have a Java JDK on your `PATH`. - -Vert.x supports Java from 8 to 17. - -NOTE: The JDK is required to support on the fly compilation of Java code. - -You can now run verticles by using the `vertx run` command. Here are some examples: - ----- -# Run a JavaScript verticle -vertx run my_verticle.js - -# Run a Ruby verticle -vertx run a_n_other_verticle.rb - -# Run a Groovy script verticle, clustered -vertx run FooVerticle.groovy -cluster ----- - -You can even run Java source verticles without compiling them first! - ----- -vertx run SomeJavaSourceFile.java ----- - -Vert.x will compile the Java source file on the fly before running it. This is really useful for quickly -prototyping verticles and great for demos. No need to set-up a Maven or Gradle build first to get going! - -For full information on the various options available when executing `vertx` on the command line, -type `vertx` at the command line. - === Causing Vert.x to exit Threads maintained by Vert.x instances are not daemon threads so they will prevent the JVM from exiting. @@ -670,323 +613,6 @@ order to gather metrics. For more information on this, please consult the You can also specify a metrics factory programmatically if embedding Vert.x using {@link io.vertx.core.metrics.MetricsOptions#setFactory(io.vertx.core.spi.VertxMetricsFactory)}. -== The 'vertx' command line - -The `vertx` command is used to interact with Vert.x from the command line. It's main use is to run Vert.x verticles. -To do this you need to download and install a Vert.x distribution, and add the `bin` directory of the installation -to your `PATH` environment variable. Also make sure you have a Java JDK on your `PATH`. - -Vert.x supports Java from 8 to 17. - -NOTE: The JDK is required to support on the fly compilation of Java code. - -=== Run verticles - -You can run raw Vert.x verticles directly from the command line using `vertx run`. Here is a couple of examples of -the `run` _command_: - -[source] ----- -vertx run my-verticle.js (1) -vertx run my-verticle.groovy (2) -vertx run my-verticle.rb (3) - -vertx run io.vertx.example.MyVerticle (4) -vertx run io.vertx.example.MVerticle -cp my-verticle.jar (5) - -vertx run MyVerticle.java (6) ----- -1. Deploys a JavaScript verticle -2. Deploys a Groovy verticle -3. Deploys a Ruby verticle -4. Deploys an already compiled Java verticle. Classpath root is the current directory -5. Deploys a verticle packaged in a Jar, the jar need to be in the classpath -6. Compiles the Java source and deploys it - -As you can see in the case of Java, the name can either be the fully qualified class name of the verticle, or -you can specify the Java Source file directly and Vert.x compiles it for you. - -You can also prefix the verticle with the name of the language implementation to use. For example if the verticle is -a compiled Groovy class, you prefix it with `groovy:` so that Vert.x knows it's a Groovy class not a Java class. - -[source] ----- -vertx run groovy:io.vertx.example.MyGroovyVerticle ----- - -The `vertx run` command can take a few optional parameters, they are: - - * `-options ` - Provides the Vert.x options. - `options` is the name of a JSON file that represents the Vert.x options, or a JSON string. This is optional. - * `-conf ` - Provides some configuration to the verticle. - `config` is the name of a JSON file that represents the configuration for the verticle, or a JSON string. This is optional. - * `-cp ` - The path on which to search for the verticle and any other resources used by the verticle. This - defaults to `.` (current directory). If your verticle references other scripts, classes or other resources - (e.g. jar files) then make sure these are on this path. The path can contain multiple path entries separated by - `:` (colon) or `;` (semi-colon) depending on the operating system. Each path entry can be an absolute or relative - path to a directory containing scripts, or absolute or relative filenames for jar or zip files. An example path - might be `-cp classes:lib/otherscripts:jars/myjar.jar:jars/otherjar.jar`. Always use the path to reference any - resources that your verticle requires. Do **not** put them on the system classpath as this can cause isolation - issues between deployed verticles. -* `-instances ` - The number of instances of the verticle to instantiate. Each verticle instance is -strictly single threaded so to scale your application across available cores you might want to deploy more than -one instance. If omitted a single instance will be deployed. - * `-worker` - This option determines whether the verticle is a worker verticle or not. - * `-cluster` - This option determines whether the Vert.x instance will attempt to form a cluster with other Vert.x - instances on the network. Clustering Vert.x instances allows Vert.x to form a distributed event bus with - other nodes. Default is `false` (not clustered). - * `-cluster-port` - If the `cluster` option has also been specified then this determines which port will be bound for - cluster communication with other Vert.x instances. Default is `0` - which means '_choose a free random port_'. You - don't usually need to specify this parameter unless you really need to bind to a specific port. - * `-cluster-host` - If the `cluster` option has also been specified then this determines which host address will be - bound for cluster communication with other Vert.x instances. If not set, the clustered eventbus tries to bind to the - same host as the underlying cluster manager. As a last resort, an address will be picked among the available network - interfaces. - * `-cluster-public-port` - If the `cluster` option has also been specified then this determines which port will be advertised for - cluster communication with other Vert.x instances. Default is `-1`, which means same as `cluster-port`. - * `-cluster-public-host` - If the `cluster` option has also been specified then this determines which host address will be advertised for - cluster communication with other Vert.x instances. If not specified, Vert.x uses the value of `cluster-host`. - * `-ha` - if specified the verticle will be deployed as high availability (HA) deployment. See related section - for more details - * `-quorum` - used in conjunction with `-ha`. It specifies the minimum number of nodes in the cluster for any _HA - deploymentIDs_ to be active. Defaults to 0. - * `-hagroup` - used in conjunction with `-ha`. It specifies the HA group this node will join. There can be - multiple HA groups in a cluster. Nodes will only failover to other nodes in the same group. The default value is ` - +++__DEFAULT__+++` - -You can also set system properties using: `-Dkey=value`. - -Here are some more examples: - -Run a JavaScript verticle server.js with default settings -[source] ----- -vertx run server.js ----- - -Run 10 instances of a pre-compiled Java verticle specifying classpath -[source] ----- -vertx run com.acme.MyVerticle -cp "classes:lib/myjar.jar" -instances 10 ----- - -Run 10 instances of a Java verticle by source _file_ -[source] ----- -vertx run MyVerticle.java -instances 10 ----- - -Run 20 instances of a ruby worker verticle -[source] ----- -vertx run order_worker.rb -instances 20 -worker ----- - -Run two JavaScript verticles on the same machine and let them cluster together with each other and any other servers -on the network -[source] ----- -vertx run handler.js -cluster -vertx run sender.js -cluster ----- - -Run a Ruby verticle passing it some config -[source] ----- -vertx run my_verticle.rb -conf my_verticle.conf ----- -Where `my_verticle.conf` might contain something like: - -[source, json] ----- -{ - "name": "foo", - "num_widgets": 46 -} ----- - -The config will be available inside the verticle via the core API. - -When using the high-availability feature of vert.x you may want to create a _bare_ instance of vert.x. This -instance does not deploy any verticles when launched, but will receive a verticle if another node of the cluster -dies. To create a _bare_ instance, launch: - -[source] ----- -vertx bare ----- - -Depending on your cluster configuration, you may have to append the `cluster-host` and `cluster-port` parameters. - -=== Executing a Vert.x application packaged as a fat jar - -A _fat jar_ is an executable jar embedding its dependencies. This means you don't have to have Vert.x pre-installed -on the machine on which you execute the jar. Like any executable Java jar it can be executed with. - -[source] ----- -java -jar my-application-fat.jar ----- - -There is nothing really Vert.x specific about this, you could do this with any Java application - -You can either create your own main class and specify that in the manifest, but it's recommended that you write your -code as verticles and use the Vert.x {@link io.vertx.core.Launcher} class (`io.vertx.core.Launcher`) as your main -class. This is the same main class used when running Vert.x at the command line and therefore allows you to -specify command line arguments, such as `-instances` in order to scale your application more easily. - -To deploy your verticle in a _fatjar_ like this you must have a _manifest_ with: - -* `Main-Class` set to `io.vertx.core.Launcher` -* `Main-Verticle` specifying the main verticle (fully qualified class name or script file name) - -You can also provide the usual command line arguments that you would pass to `vertx run`: -[source] ----- -java -jar my-verticle-fat.jar -cluster -conf myconf.json -java -jar my-verticle-fat.jar -cluster -conf myconf.json -cp path/to/dir/conf/cluster_xml ----- - -NOTE: Please consult the Maven/Gradle simplest and Maven/Gradle verticle examples in the examples repository for -examples of building applications as fatjars. - -A fat jar executes the `run` command, by default. - -=== Displaying version of Vert.x -To display the vert.x version, just launch: - -[source] ----- -vertx version ----- - -=== Other commands - -The `vertx` command line and the `Launcher` also provide other _commands_ in addition to `run` and `version`: - -You can create a `bare` instance using: - -[source] ----- -vertx bare -# or -java -jar my-verticle-fat.jar bare ----- - -You can also start an application in background using: - -[source] ----- -java -jar my-verticle-fat.jar start --vertx-id=my-app-name ----- - -If `my-app-name` is not set, a random id will be generated, and printed on the command prompt. You can pass `run` -options to the `start` command: - -[source] ----- -java -jar my-verticle-fat.jar start —-vertx-id=my-app-name -cluster ----- - -Once launched in background, you can stop it with the `stop` command: - -[source] ----- -java -jar my-verticle-fat.jar stop my-app-name ----- - -You can also list the vert.x application launched in background using: - -[source] ----- -java -jar my-verticle-fat.jar list ----- - -The `start`, `stop` and `list` command are also available from the `vertx` tool. The start` command supports a couple of options: - - * `vertx-id` : the application id, uses a random UUID if not set - * `java-opts` : the Java Virtual Machine options, uses the `JAVA_OPTS` environment variable if not set. - * `redirect-output` : redirect the spawned process output and error streams to the parent process streams. - - If option values contain spaces, don't forget to wrap the value between `""` (double-quotes). - - As the `start` command spawns a new process, the java options passed to the JVM are not propagated, so you **must** - use `java-opts` to configure the JVM (`-X`, `-D`...). If you use the `CLASSPATH` environment variable, be sure it - contains all the required jars (vertx-core, your jars and all the dependencies). - -The set of commands is extensible, refer to the <> section. - -=== Live Redeploy - -When developing it may be convenient to automatically redeploy your application upon file changes. The `vertx` -command line tool and more generally the {@link io.vertx.core.Launcher} class offers this feature. Here are some -examples: - -[source] ----- -vertx run MyVerticle.groovy --redeploy="**/*.groovy" --launcher-class=io.vertx.core.Launcher -vertx run MyVerticle.groovy --redeploy="**/*.groovy,**/*.rb" --launcher-class=io.vertx.core.Launcher -java io.vertx.core.Launcher run org.acme.MyVerticle --redeploy="**/*.class" --launcher-class=io.vertx.core -.Launcher -cp ... ----- - -The redeployment process is implemented as follows. First your application is launched as a background application -(with the `start` command). On matching file changes, the process is stopped and the application is restarted. -This avoids leaks, as the process is restarted. - -To enable the live redeploy, pass the `--redeploy` option to the `run` command. The `--redeploy` indicates the -set of file to _watch_. This set can use Ant-style patterns (with `\**`, `*` and `?`). You can specify -several sets by separating them using a comma (`,`). Patterns are relative to the current working directory. - -Parameters passed to the `run` command are passed to the application. Java Virtual Machine options can be -configured using `--java-opts`. For instance, to pass the `conf` parameter or a system property, you need to -use: `--java-opts="-conf=my-conf.json -Dkey=value"` - -The `--launcher-class` option determine with with _main_ class the application is launcher. It's generally -{@link io.vertx.core.Launcher}, but you have use you own _main_. - -The redeploy feature can be used in your IDE: - -* Eclipse - create a _Run_ configuration, using the `io.vertx.core.Launcher` class a _main class_. In the _Program -arguments_ area (in the _Arguments_ tab), write `run your-verticle-fully-qualified-name --redeploy=\**/*.java ---launcher-class=io.vertx.core.Launcher`. You can also add other parameters. The redeployment works smoothly as -Eclipse incrementally compiles your files on save. -* IntelliJ - create a _Run_ configuration (_Application_), set the _Main class_ to `io.vertx.core.Launcher`. In -the Program arguments write: `run your-verticle-fully-qualified-name --redeploy=\**/*.class ---launcher-class=io.vertx.core.Launcher`. To trigger the redeployment, you need to _make_ the project or -the module explicitly (_Build_ menu -> _Make project_). - -To debug your application, create your run configuration as a remote application and configure the debugger -using `--java-opts`. However, don't forget to re-plug the debugger after every redeployment as a new process is -created every time. - -You can also hook your build process in the redeploy cycle: - -[source] ----- -java -jar target/my-fat-jar.jar --redeploy="**/*.java" --on-redeploy="mvn package" -java -jar build/libs/my-fat-jar.jar --redeploy="src/**/*.java" --on-redeploy='./gradlew shadowJar' ----- - -The "on-redeploy" option specifies a command invoked after the shutdown of the application and before the -restart. So you can hook your build tool if it updates some runtime artifacts. For instance, you can launch `gulp` -or `grunt` to update your resources. Don't forget that passing parameters to your application requires the -`--java-opts` param: - -[source] ----- -java -jar target/my-fat-jar.jar --redeploy="**/*.java" --on-redeploy="mvn package" --java-opts="-Dkey=val" -java -jar build/libs/my-fat-jar.jar --redeploy="src/**/*.java" --on-redeploy='./gradlew shadowJar' --java-opts="-Dkey=val" ----- - -The redeploy feature also supports the following settings: - -* `redeploy-scan-period` : the file system check period (in milliseconds), 250ms by default -* `redeploy-grace-period` : the amount of time (in milliseconds) to wait between 2 re-deployments, 1000ms by default -* `redeploy-termination-period` : the amount of time to wait after having stopped the application (before -launching user command). This is useful on Windows, where the process is not killed immediately. The time is given -in milliseconds. 0 ms by default. - == Cluster Managers In Vert.x a cluster manager is used for various functions including: @@ -1106,147 +732,6 @@ may have not consumed the complete payload (the connection was cut before you we include::override/hostname-resolution.adoc[] -== High Availability and Fail-Over - -Vert.x allows you to run your verticles with high availability (HA) support. In that case, when a vert.x -instance running a verticle dies abruptly, the verticle is migrated to another vertx instance. The vert.x -instances must be in the same cluster. - -=== Automatic failover - -When vert.x runs with _HA_ enabled, if a vert.x instance where a verticle runs fails or dies, the verticle is -redeployed automatically on another vert.x instance of the cluster. We call this _verticle fail-over_. - -To run vert.x with the _HA_ enabled, just add the `-ha` flag to the command line: - -[source] ----- -vertx run my-verticle.js -ha ----- - -Now for HA to work, you need more than one Vert.x instances in the cluster, so let's say you have another -Vert.x instance that you have already started, for example: - -[source] ----- -vertx run my-other-verticle.js -ha ----- - -If the Vert.x instance that is running `my-verticle.js` now dies (you can test this by killing the process -with `kill -9`), the Vert.x instance that is running `my-other-verticle.js` will automatic deploy `my-verticle -.js` so now that Vert.x instance is running both verticles. - -NOTE: the migration is only possible if the second vert.x instance has access to the verticle file (here -`my-verticle.js`). - -IMPORTANT: Please note that cleanly closing a Vert.x instance will not cause failover to occur, e.g. `CTRL-C` -or `kill -SIGINT` - -You can also start _bare_ Vert.x instances - i.e. instances that are not initially running any verticles, they -will also failover for nodes in the cluster. To start a bare instance you simply do: - -[source] ----- -vertx run -ha ----- - -When using the `-ha` switch you do not need to provide the `-cluster` switch, as a cluster is assumed if you -want HA. - -NOTE: depending on your cluster configuration, you may need to customize the cluster manager configuration -(Hazelcast by default), and/or add the `cluster-host` and `cluster-port` parameters. - -=== HA groups - -When running a Vert.x instance with HA you can also optional specify a _HA group_. A HA group denotes a -logical group of nodes in the cluster. Only nodes with the same HA group will failover onto one another. If -you don't specify a HA group the default group `+++__DEFAULT__+++` is used. - -To specify an HA group you use the `-hagroup` switch when running the verticle, e.g. - -[source] ----- -vertx run my-verticle.js -ha -hagroup my-group ----- - -Let's look at an example: - -In a first terminal: - -[source] ----- -vertx run my-verticle.js -ha -hagroup g1 ----- - -In a second terminal, let's run another verticle using the same group: - -[source] ----- -vertx run my-other-verticle.js -ha -hagroup g1 ----- - -Finally, in a third terminal, launch another verticle using a different group: - -[source] ----- -vertx run yet-another-verticle.js -ha -hagroup g2 ----- - -If we kill the instance in terminal 1, it will fail over to the instance in terminal 2, not the instance in -terminal 3 as that has a different group. - -If we kill the instance in terminal 3, it won't get failed over as there is no other vert.x instance in that -group. - -=== Dealing with network partitions - Quorum - -The HA implementation also supports quorum. A quorum is the minimum number of votes that a distributed -transaction has to obtain in order to be allowed to perform an operation in a distributed system. - -When starting a Vert.x instance you can instruct it that it requires a `quorum` before any HA deployments will -be deployed. In this context, a quorum is a minimum number of nodes for a particular group in the cluster. -Typically you chose your quorum size to `Q = 1 + N/2` where `N` is the number of nodes in the group. If there -are less than `Q` nodes in the cluster the HA deployments will undeploy. They will redeploy again if/when a -quorum is re-attained. By doing this you can prevent against network partitions, a.k.a. _split brain_. - -There is more information on quorum http://en.wikipedia.org/wiki/Quorum_(distributed_computing)[here]. - -To run vert.x instances with a quorum you specify `-quorum` on the command line, e.g. - -In a first terminal: -[source] ----- -vertx run my-verticle.js -ha -quorum 3 ----- - -At this point the Vert.x instance will start but not deploy the module (yet) because there is only one node -in the cluster, not 3. - -In a second terminal: -[source] ----- -vertx run my-other-verticle.js -ha -quorum 3 ----- - -At this point the Vert.x instance will start but not deploy the module (yet) because there are only two nodes -in the cluster, not 3. - -In a third console, you can start another instance of vert.x: - -[source] ----- -vertx run yet-another-verticle.js -ha -quorum 3 ----- - -Yay! - we have three nodes, that's a quorum. At this point the modules will automatically deploy on all -instances. - -If we now close or kill one of the nodes the modules will automatically undeploy on the other nodes, as there -is no longer a quorum. - -Quorum can also be used in conjunction with ha groups. In that case, quorum are resolved for each particular -group. - == Native transports Vert.x can run with http://netty.io/wiki/native-transports.html[native transports] (when available) on BSD (OSX) and Linux: @@ -1381,105 +866,6 @@ follow security best practice, especially if your service is public facing. For example you should always run them in a DMZ and with an user account that has limited rights in order to limit the extent of damage in case the service was compromised. -== Vert.x Command Line Interface API - -include::cli.adoc[] - -== The vert.x Launcher - -The vert.x {@link io.vertx.core.Launcher} is used in _fat jar_ as main class, and by the `vertx` command line -utility. It executes a set of _commands_ such as _run_, _bare_, _start_... - -=== Extending the vert.x Launcher - -You can extend the set of command by implementing your own {@link io.vertx.core.spi.launcher.Command} (in Java only): - -[source, java] ----- -@Name("my-command") -@Summary("A simple hello command.") -public class MyCommand extends DefaultCommand { - - private String name; - - @Option(longName = "name", required = true) - public void setName(String n) { - this.name = n; - } - - @Override - public void run() throws CLIException { - System.out.println("Hello " + name); - } -} ----- - -You also need an implementation of {@link io.vertx.core.spi.launcher.CommandFactory}: - -[source, java] ----- -public class HelloCommandFactory extends DefaultCommandFactory { - public HelloCommandFactory() { - super(HelloCommand.class); - } -} ----- - -Then, create the `src/main/resources/META-INF/services/io.vertx.core.spi.launcher.CommandFactory` and add a line -indicating the fully qualified name of the factory: - ----- -io.vertx.core.launcher.example.HelloCommandFactory ----- - -Builds the jar containing the command. Be sure to includes the SPI file -(`META-INF/services/io.vertx.core.spi.launcher.CommandFactory`). - -Then, place the jar containing the command into the classpath of your fat-jar (or include it inside) or in the `lib` -directory of your vert.x distribution, and you would be able to execute: - -[source] ----- -vertx hello vert.x -java -jar my-fat-jar.jar hello vert.x ----- - -=== Using the Launcher in fat jars - -To use the {@link io.vertx.core.Launcher} class in a _fat-jar_ just set the `Main-Class` of the _MANIFEST_ to -`io.vertx.core.Launcher`. In addition, set the `Main-Verticle` _MANIFEST_ entry to the name of your main verticle. - -By default, it executed the `run` command. However, you can configure the default command by setting the -`Main-Command` _MANIFEST_ entry. The default command is used if the _fat jar_ is launched without a command. - -=== Sub-classing the Launcher - -You can also create a sub-class of {@link io.vertx.core.Launcher} to start your application. The class has been -designed to be easily extensible. - -A {@link io.vertx.core.Launcher} sub-class can: - -* customize the vert.x configuration in {@link io.vertx.core.Launcher#beforeStartingVertx(io.vertx.core.VertxOptions)} -* retrieve the vert.x instance created by the "run" or "bare" command by -overriding {@link io.vertx.core.Launcher#afterStartingVertx(io.vertx.core.Vertx)} -* configure the default verticle and command with -{@link io.vertx.core.impl.launcher.VertxCommandLauncher#getMainVerticle()} and -{@link io.vertx.core.impl.launcher.VertxCommandLauncher#getDefaultCommand()} -* add / remove commands using {@link io.vertx.core.impl.launcher.VertxCommandLauncher#register(java.lang.Class)} -and {@link io.vertx.core.impl.launcher.VertxCommandLauncher#unregister(java.lang.String)} - -=== Launcher and exit code - -When you use the {@link io.vertx.core.Launcher} class as main class, it uses the following exit code: - -* `0` if the process ends smoothly, or if an uncaught error is thrown -* `1` for general purpose error -* `11` if Vert.x cannot be initialized -* `12` if a spawn process cannot be started, found or stopped. This error code is used by the `start` and -`stop` command -* `14` if the system configuration is not meeting the system requirement (shc as java not found) -* `15` if the main verticle cannot be deployed - == Configuring Vert.x cache When Vert.x needs to read a file from the classpath (embedded in a fat jar, in a jar form the classpath or a file @@ -1494,8 +880,6 @@ application with: [source] ---- -vertx run my.Verticle -Dvertx.cacheDirBase=/tmp/vertx-cache -# or java -jar my-fat.jar vertx.cacheDirBase=/tmp/vertx-cache ---- diff --git a/src/main/asciidoc/net.adoc b/src/main/asciidoc/net.adoc index c1d9a3d30bb..300063679da 100644 --- a/src/main/asciidoc/net.adoc +++ b/src/main/asciidoc/net.adoc @@ -204,14 +204,6 @@ You can instantiate more instances programmatically in your code: {@link examples.NetExamples#example11} ---- -or, you can simply deploy more instances of your server verticle by using the `-instances` option -on the command line: - -[source] ----- -> vertx run com.mycompany.MyVerticle -instances 10 ----- - Once you do this you will find the echo server works functionally identically to before, but all your cores on your server can be utilised and more work can be handled. diff --git a/src/main/asciidoc/override/configuring-eventbus.adoc b/src/main/asciidoc/override/configuring-eventbus.adoc index 64a7d15fe31..e73aa799ff7 100644 --- a/src/main/asciidoc/override/configuring-eventbus.adoc +++ b/src/main/asciidoc/override/configuring-eventbus.adoc @@ -1,4 +1,4 @@ -The event bus can be configured. It is particularly useful when the event bus is clustered. +The event bus can be configured.It is particularly useful when the event bus is clustered. Under the hood the event bus uses TCP connections to send and receive messages, so the {@link io.vertx.core.eventbus.EventBusOptions} let you configure all aspects of these TCP connections. As the event bus acts as a server and client, the configuration is close to {@link io.vertx.core.net.NetClientOptions} and {@link io.vertx.core.net.NetServerOptions}. @@ -9,12 +9,12 @@ As the event bus acts as a server and client, the configuration is close to {@li The previous snippet depicts how you can use SSL connections for the event bus, instead of plain TCP connections. -**WARNING**: to enforce the security in clustered mode, you **must** configure the cluster manager to use encryption or enforce security. +WARNING: To enforce the security in clustered mode, you **must** configure the cluster manager to use encryption or enforce security. Refer to the documentation of the cluster manager for further details. The event bus configuration needs to be consistent in all the cluster nodes. -The {@link io.vertx.core.eventbus.EventBusOptions} also lets you specify whether or not the event bus is clustered, the port and host. +The {@link io.vertx.core.eventbus.EventBusOptions} also lets you specify whether the event bus is clustered, the port and host. When used in containers, you can also configure the public host and port: diff --git a/src/main/java/examples/cli/AnnotatedCli.java b/src/main/java/examples/cli/AnnotatedCli.java deleted file mode 100644 index b45d5f7c86f..00000000000 --- a/src/main/java/examples/cli/AnnotatedCli.java +++ /dev/null @@ -1,45 +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 examples.cli; - -import io.vertx.core.cli.annotations.*; - -/** - * An example of annotated cli. - * @author Clement Escoffier - */ -// tag::content[] -@Name("some-name") -@Summary("some short summary.") -@Description("some long description") -public class AnnotatedCli { - - private boolean flag; - private String name; - private String arg; - - @Option(shortName = "f", flag = true) - public void setFlag(boolean flag) { - this.flag = flag; - } - - @Option(longName = "name") - public void setName(String name) { - this.name = name; - } - - @Argument(index = 0) - public void setArg(String arg) { - this.arg = arg; - } -} -// end::content[] diff --git a/src/main/java/examples/cli/CLIExamples.java b/src/main/java/examples/cli/CLIExamples.java deleted file mode 100644 index a343cb4a8dd..00000000000 --- a/src/main/java/examples/cli/CLIExamples.java +++ /dev/null @@ -1,155 +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 examples.cli; - -import io.vertx.core.cli.Argument; -import io.vertx.core.cli.CLI; -import io.vertx.core.cli.CommandLine; -import io.vertx.core.cli.Option; - -import java.io.PrintStream; -import java.util.Collections; -import java.util.List; - -/** - * @author Clement Escoffier - */ -public class CLIExamples { - - public void example1() { - CLI cli = CLI.create("copy") - .setSummary("A command line interface to copy files.") - .addOption(new Option() - .setLongName("directory") - .setShortName("R") - .setDescription("enables directory support") - .setFlag(true)) - .addArgument(new Argument() - .setIndex(0) - .setDescription("The source") - .setArgName("source")) - .addArgument(new Argument() - .setIndex(1) - .setDescription("The destination") - .setArgName("target")); - } - - public void example2() { - CLI cli = CLI.create("some-name") - .setSummary("A command line interface illustrating the options valuation.") - .addOption(new Option() - .setLongName("flag").setShortName("f").setFlag(true).setDescription("a flag")) - .addOption(new Option() - .setLongName("single").setShortName("s").setDescription("a single-valued option")) - .addOption(new Option() - .setLongName("multiple").setShortName("m").setMultiValued(true) - .setDescription("a multi-valued option")); - } - - public void example3() { - CLI cli = CLI.create("some-name") - .addOption(new Option() - .setLongName("mandatory") - .setRequired(true) - .setDescription("a mandatory option")); - } - - public void example4() { - CLI cli = CLI.create("some-name") - .addOption(new Option() - .setLongName("optional") - .setDefaultValue("hello") - .setDescription("an optional option with a default value")); - } - - public void example41() { - CLI cli = CLI.create("some-name") - .addOption(new Option() - .setLongName("color") - .setDefaultValue("green") - .addChoice("blue").addChoice("red").addChoice("green") - .setDescription("a color")); - } - - public void example5() { - CLI cli = CLI.create("some-name") - .addArgument(new Argument() - .setIndex(0) - .setDescription("the first argument") - .setArgName("arg1")) - .addArgument(new Argument() - .setIndex(1) - .setDescription("the second argument") - .setArgName("arg2")); - } - - public void example51() { - CLI cli = CLI.create("some-name") - // will have the index 0 - .addArgument(new Argument() - .setDescription("the first argument") - .setArgName("arg1")) - // will have the index 1 - .addArgument(new Argument() - .setDescription("the second argument") - .setArgName("arg2")); - } - - public void example6() { - CLI cli = CLI.create("copy") - .setSummary("A command line interface to copy files.") - .addOption(new Option() - .setLongName("directory") - .setShortName("R") - .setDescription("enables directory support") - .setFlag(true)) - .addArgument(new Argument() - .setIndex(0) - .setDescription("The source") - .setArgName("source")) - .addArgument(new Argument() - .setIndex(0) - .setDescription("The destination") - .setArgName("target")); - - StringBuilder builder = new StringBuilder(); - cli.usage(builder); - } - - public void example7(CLI cli, List userCommandLineArguments) { - CommandLine commandLine = cli.parse(userCommandLineArguments); - } - - public void example8(CLI cli, List userCommandLineArguments) { - CommandLine commandLine = cli.parse(userCommandLineArguments); - String opt = commandLine.getOptionValue("my-option"); - boolean flag = commandLine.isFlagEnabled("my-flag"); - String arg0 = commandLine.getArgumentValue(0); - } - - public void example9(PrintStream stream) { - CLI cli = CLI.create("test") - .addOption( - new Option().setLongName("help").setShortName("h").setFlag(true).setHelp(true)) - .addOption( - new Option().setLongName("mandatory").setRequired(true)); - - CommandLine line = cli.parse(Collections.singletonList("-h")); - - // The parsing does not fail and let you do: - if (!line.isValid() && line.isAskingForHelp()) { - StringBuilder builder = new StringBuilder(); - cli.usage(builder); - stream.print(builder.toString()); - } - } -} diff --git a/src/main/java/examples/cli/MyCommand.java b/src/main/java/examples/cli/MyCommand.java deleted file mode 100644 index c6bbce1fdc1..00000000000 --- a/src/main/java/examples/cli/MyCommand.java +++ /dev/null @@ -1,39 +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 examples.cli; - -// tag::content[] - -import io.vertx.core.cli.CLIException; -import io.vertx.core.cli.annotations.Name; -import io.vertx.core.cli.annotations.Option; -import io.vertx.core.cli.annotations.Summary; -import io.vertx.core.spi.launcher.DefaultCommand; - -@Name("my-command") -@Summary("A simple hello command.") -public class MyCommand extends DefaultCommand { - - private String name; - - @Option(longName = "name", required = true) - public void setName(String n) { - this.name = n; - } - - @Override - public void run() throws CLIException { - System.out.println("Hello " + name); - } -} - -// end::content[] diff --git a/src/main/java/examples/cli/TypedCLIExamples.java b/src/main/java/examples/cli/TypedCLIExamples.java deleted file mode 100644 index feb10c93c73..00000000000 --- a/src/main/java/examples/cli/TypedCLIExamples.java +++ /dev/null @@ -1,87 +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 examples.cli; - -import io.vertx.core.cli.CLI; -import io.vertx.core.cli.CommandLine; -import io.vertx.core.cli.TypedArgument; -import io.vertx.core.cli.TypedOption; -import io.vertx.core.cli.annotations.CLIConfigurator; -import io.vertx.core.cli.converters.Converter; -import io.vertx.docgen.Source; - -import java.io.File; -import java.util.List; - -/** - * @author Clement Escoffier - */ -@Source(translate = false) -public class TypedCLIExamples { - - public void example1() { - CLI cli = CLI.create("copy") - .setSummary("A command line interface to copy files.") - .addOption(new TypedOption() - .setType(Boolean.class) - .setLongName("directory") - .setShortName("R") - .setDescription("enables directory support") - .setFlag(true)) - .addArgument(new TypedArgument() - .setType(File.class) - .setIndex(0) - .setDescription("The source") - .setArgName("source")) - .addArgument(new TypedArgument() - .setType(File.class) - .setIndex(0) - .setDescription("The destination") - .setArgName("target")); - } - - public void example2(CLI cli, List userCommandLineArguments) { - CommandLine commandLine = cli.parse(userCommandLineArguments); - boolean flag = commandLine.getOptionValue("R"); - File source = commandLine.getArgumentValue("source"); - File target = commandLine.getArgumentValue("target"); - } - - public void example3() { - CLI cli = CLI.create("some-name") - .addOption(new TypedOption() - .setType(Person.class) - .setConverter(new PersonConverter()) - .setLongName("person")); - } - - public void example4(List userCommandLineArguments) { - CLI cli = CLI.create(AnnotatedCli.class); - CommandLine commandLine = cli.parse(userCommandLineArguments); - AnnotatedCli instance = new AnnotatedCli(); - CLIConfigurator.inject(commandLine, instance); - } - - private class Person { - - } - - private class PersonConverter implements Converter { - - @Override - public Person fromString(String s) { - return null; - } - } - - -} diff --git a/src/main/java/examples/cli/package-info.java b/src/main/java/examples/cli/package-info.java deleted file mode 100644 index 52a1c953f99..00000000000 --- a/src/main/java/examples/cli/package-info.java +++ /dev/null @@ -1,18 +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 - */ - -/** - * @author Julien Viet - */ -@Source -package examples.cli; - -import io.vertx.docgen.Source; From dcf66cee588e539274d8825a2c360e8a4311ef49 Mon Sep 17 00:00:00 2001 From: Thomas Segismont Date: Fri, 7 Jul 2023 18:21:39 +0200 Subject: [PATCH 030/264] Remove CLI and Launcher production and test code We have to deprecate the processArgs method because Vert.x is no longer tightly coupled to the CLI. Signed-off-by: Thomas Segismont --- .../io/vertx/core/cli/ArgumentConverter.java | 81 -- .../io/vertx/core/cli/OptionConverter.java | 129 --- .../java/io/vertx/core/AbstractVerticle.java | 8 +- src/main/java/io/vertx/core/Context.java | 19 +- src/main/java/io/vertx/core/Launcher.java | 116 --- .../core/cli/AmbiguousOptionException.java | 55 -- src/main/java/io/vertx/core/cli/Argument.java | 260 ------ src/main/java/io/vertx/core/cli/CLI.java | 284 ------ .../java/io/vertx/core/cli/CLIException.java | 39 - .../java/io/vertx/core/cli/CommandLine.java | 205 ----- .../vertx/core/cli/InvalidValueException.java | 87 -- .../core/cli/MissingOptionException.java | 45 - .../vertx/core/cli/MissingValueException.java | 62 -- src/main/java/io/vertx/core/cli/Option.java | 435 --------- .../java/io/vertx/core/cli/TypedArgument.java | 142 --- .../java/io/vertx/core/cli/TypedOption.java | 200 ----- .../vertx/core/cli/UsageMessageFormatter.java | 705 --------------- .../vertx/core/cli/annotations/Argument.java | 46 - .../core/cli/annotations/CLIConfigurator.java | 277 ------ .../core/cli/annotations/ConvertedBy.java | 36 - .../core/cli/annotations/DefaultValue.java | 36 - .../core/cli/annotations/Description.java | 33 - .../io/vertx/core/cli/annotations/Hidden.java | 29 - .../io/vertx/core/cli/annotations/Name.java | 40 - .../io/vertx/core/cli/annotations/Option.java | 84 -- .../core/cli/annotations/ParsedAsList.java | 37 - .../vertx/core/cli/annotations/Summary.java | 34 - .../core/cli/annotations/package-info.java | 12 - .../core/cli/converters/BooleanConverter.java | 49 - .../cli/converters/CharacterConverter.java | 46 - .../converters/ConstructorBasedConverter.java | 74 -- .../vertx/core/cli/converters/Converter.java | 24 - .../vertx/core/cli/converters/Converters.java | 127 --- .../cli/converters/FromBasedConverter.java | 84 -- .../converters/FromStringBasedConverter.java | 84 -- .../cli/converters/ValueOfBasedConverter.java | 83 -- .../io/vertx/core/cli/impl/DefaultCLI.java | 254 ------ .../core/cli/impl/DefaultCommandLine.java | 379 -------- .../io/vertx/core/cli/impl/DefaultParser.java | 603 ------------- .../vertx/core/cli/impl/ReflectionUtils.java | 68 -- .../java/io/vertx/core/cli/package-info.java | 12 - .../io/vertx/core/impl/AddressResolver.java | 7 +- .../io/vertx/core/impl/cpu/CpuCoreSensor.java | 9 +- .../core/impl/launcher/CommandLineUtils.java | 66 -- .../launcher/ServiceCommandFactoryLoader.java | 53 -- .../impl/launcher/VertxCommandLauncher.java | 479 ---------- .../impl/launcher/VertxLifecycleHooks.java | 82 -- .../impl/launcher/commands/BareCommand.java | 503 ----------- .../launcher/commands/BareCommandFactory.java | 29 - .../launcher/commands/ClasspathHandler.java | 175 ---- .../impl/launcher/commands/ExecUtils.java | 170 ---- .../impl/launcher/commands/FileSelector.java | 365 -------- .../impl/launcher/commands/ListCommand.java | 131 --- .../launcher/commands/ListCommandFactory.java | 28 - .../impl/launcher/commands/RunCommand.java | 454 ---------- .../launcher/commands/RunCommandFactory.java | 29 - .../impl/launcher/commands/StartCommand.java | 197 ---- .../commands/StartCommandFactory.java | 29 - .../impl/launcher/commands/StopCommand.java | 158 ---- .../launcher/commands/StopCommandFactory.java | 29 - .../launcher/commands/VersionCommand.java | 65 -- .../commands/VersionCommandFactory.java | 29 - .../commands/VertxIsolatedDeployer.java | 88 -- .../core/impl/launcher/commands/Watcher.java | 360 -------- .../vertx/core/spi/VertxMetricsFactory.java | 9 +- .../io/vertx/core/spi/launcher/Command.java | 63 -- .../core/spi/launcher/CommandFactory.java | 42 - .../spi/launcher/CommandFactoryLookup.java | 33 - .../core/spi/launcher/DefaultCommand.java | 116 --- .../spi/launcher/DefaultCommandFactory.java | 70 -- .../core/spi/launcher/ExecutionContext.java | 93 -- .../core/CustomerLauncherLowMemoryTest.java | 147 --- .../vertx/core/IsolatingClassLoaderTest.java | 137 --- src/test/java/io/vertx/core/LauncherTest.java | 790 ---------------- .../cli/AmbiguousOptionExceptionTest.java | 37 - .../java/io/vertx/core/cli/OptionTest.java | 67 -- .../cli/converters/BooleanConverterTest.java | 66 -- .../converters/CharacterConverterTest.java | 42 - .../ConstructorBasedConverterTest.java | 32 - .../core/cli/converters/ConvertersTest.java | 111 --- .../cli/converters/CustomConverterTest.java | 34 - .../io/vertx/core/cli/converters/Person.java | 27 - .../io/vertx/core/cli/converters/Person2.java | 26 - .../io/vertx/core/cli/converters/Person3.java | 26 - .../io/vertx/core/cli/converters/Person4.java | 24 - .../core/cli/converters/Person4Converter.java | 21 - .../core/cli/impl/CLIConfiguratorTest.java | 623 ------------- .../vertx/core/cli/impl/DefaultCLITest.java | 230 ----- .../core/cli/impl/DefaultParserTest.java | 849 ------------------ .../java/io/vertx/core/cli/impl/HelloClI.java | 38 - .../cli/impl/IntensiveDefaultParserTest.java | 604 ------------- .../core/cli/impl/TypedArgumentTest.java | 175 ---- .../core/eventbus/FaultToleranceTest.java | 10 +- .../impl/launcher/DefaultCommandTest.java | 93 -- .../launcher/LauncherExtensibilityTest.java | 248 ----- .../launcher/ServiceCommandLoaderTest.java | 70 -- .../VertxCommandLineInterfaceTest.java | 308 ------- .../launcher/commands/BareCommandTest.java | 111 --- .../commands/ClasspathHandlerTest.java | 112 --- .../launcher/commands/CommandTestBase.java | 129 --- .../launcher/commands/ComplexCommand.java | 72 -- .../commands/ComplexCommandFactory.java | 20 - .../impl/launcher/commands/ExecUtilsTest.java | 115 --- .../launcher/commands/FileSelectorTest.java | 101 --- .../launcher/commands/GoodByeCommand.java | 42 - .../commands/GoodByeCommandFactory.java | 26 - .../impl/launcher/commands/Hello2Command.java | 25 - .../commands/Hello2CommandFactory.java | 23 - .../impl/launcher/commands/HelloCommand.java | 47 - .../commands/HelloCommandFactory.java | 23 - .../impl/launcher/commands/HiddenCommand.java | 49 - .../commands/HiddenCommandFactory.java | 22 - .../launcher/commands/HttpTestVerticle.java | 44 - .../commands/OptionsRecordingLauncher.java | 35 - .../commands/PriorityCommandTest.java | 44 - .../impl/launcher/commands/RedeployTest.java | 285 ------ .../launcher/commands/RunCommandTest.java | 251 ------ .../commands/ServiceCommandLookupTest.java | 54 -- .../commands/StartStopListCommandsTest.java | 327 ------- .../commands/WatcherAbsolutePathTest.java | 57 -- .../impl/launcher/commands/WatcherTest.java | 332 ------- .../verticles/FaultToleranceVerticle.java | 18 +- .../io/vertx/test/verticles/TestVerticle.java | 8 +- .../MANIFEST-Launcher-Default-Command.MF | 2 - .../MANIFEST-Launcher-Http-Verticle.MF | 2 - ...MANIFEST-Launcher-Missing-Main-Verticle.MF | 2 - .../MANIFEST-Launcher-No-Main-Verticle.MF | 1 - .../META-INF/MANIFEST-Launcher-hello.MF | 3 - .../META-INF/MANIFEST-Launcher-run.MF | 2 - .../resources/META-INF/MANIFEST-Launcher.MF | 2 - 130 files changed, 40 insertions(+), 16565 deletions(-) delete mode 100644 src/main/generated/io/vertx/core/cli/ArgumentConverter.java delete mode 100644 src/main/generated/io/vertx/core/cli/OptionConverter.java delete mode 100644 src/main/java/io/vertx/core/Launcher.java delete mode 100644 src/main/java/io/vertx/core/cli/AmbiguousOptionException.java delete mode 100644 src/main/java/io/vertx/core/cli/Argument.java delete mode 100644 src/main/java/io/vertx/core/cli/CLI.java delete mode 100644 src/main/java/io/vertx/core/cli/CLIException.java delete mode 100644 src/main/java/io/vertx/core/cli/CommandLine.java delete mode 100644 src/main/java/io/vertx/core/cli/InvalidValueException.java delete mode 100644 src/main/java/io/vertx/core/cli/MissingOptionException.java delete mode 100644 src/main/java/io/vertx/core/cli/MissingValueException.java delete mode 100644 src/main/java/io/vertx/core/cli/Option.java delete mode 100644 src/main/java/io/vertx/core/cli/TypedArgument.java delete mode 100644 src/main/java/io/vertx/core/cli/TypedOption.java delete mode 100644 src/main/java/io/vertx/core/cli/UsageMessageFormatter.java delete mode 100644 src/main/java/io/vertx/core/cli/annotations/Argument.java delete mode 100644 src/main/java/io/vertx/core/cli/annotations/CLIConfigurator.java delete mode 100644 src/main/java/io/vertx/core/cli/annotations/ConvertedBy.java delete mode 100644 src/main/java/io/vertx/core/cli/annotations/DefaultValue.java delete mode 100644 src/main/java/io/vertx/core/cli/annotations/Description.java delete mode 100644 src/main/java/io/vertx/core/cli/annotations/Hidden.java delete mode 100644 src/main/java/io/vertx/core/cli/annotations/Name.java delete mode 100644 src/main/java/io/vertx/core/cli/annotations/Option.java delete mode 100644 src/main/java/io/vertx/core/cli/annotations/ParsedAsList.java delete mode 100644 src/main/java/io/vertx/core/cli/annotations/Summary.java delete mode 100644 src/main/java/io/vertx/core/cli/annotations/package-info.java delete mode 100644 src/main/java/io/vertx/core/cli/converters/BooleanConverter.java delete mode 100644 src/main/java/io/vertx/core/cli/converters/CharacterConverter.java delete mode 100644 src/main/java/io/vertx/core/cli/converters/ConstructorBasedConverter.java delete mode 100644 src/main/java/io/vertx/core/cli/converters/Converter.java delete mode 100644 src/main/java/io/vertx/core/cli/converters/Converters.java delete mode 100644 src/main/java/io/vertx/core/cli/converters/FromBasedConverter.java delete mode 100644 src/main/java/io/vertx/core/cli/converters/FromStringBasedConverter.java delete mode 100644 src/main/java/io/vertx/core/cli/converters/ValueOfBasedConverter.java delete mode 100644 src/main/java/io/vertx/core/cli/impl/DefaultCLI.java delete mode 100644 src/main/java/io/vertx/core/cli/impl/DefaultCommandLine.java delete mode 100644 src/main/java/io/vertx/core/cli/impl/DefaultParser.java delete mode 100644 src/main/java/io/vertx/core/cli/impl/ReflectionUtils.java delete mode 100644 src/main/java/io/vertx/core/cli/package-info.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/CommandLineUtils.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/ServiceCommandFactoryLoader.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/VertxCommandLauncher.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/VertxLifecycleHooks.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/BareCommand.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/BareCommandFactory.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/ClasspathHandler.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/ExecUtils.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/FileSelector.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/ListCommand.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/ListCommandFactory.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/RunCommand.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/RunCommandFactory.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/StartCommand.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/StartCommandFactory.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/StopCommand.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/StopCommandFactory.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/VersionCommand.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/VersionCommandFactory.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/VertxIsolatedDeployer.java delete mode 100644 src/main/java/io/vertx/core/impl/launcher/commands/Watcher.java delete mode 100644 src/main/java/io/vertx/core/spi/launcher/Command.java delete mode 100644 src/main/java/io/vertx/core/spi/launcher/CommandFactory.java delete mode 100644 src/main/java/io/vertx/core/spi/launcher/CommandFactoryLookup.java delete mode 100644 src/main/java/io/vertx/core/spi/launcher/DefaultCommand.java delete mode 100644 src/main/java/io/vertx/core/spi/launcher/DefaultCommandFactory.java delete mode 100644 src/main/java/io/vertx/core/spi/launcher/ExecutionContext.java delete mode 100644 src/test/java/io/vertx/core/CustomerLauncherLowMemoryTest.java delete mode 100644 src/test/java/io/vertx/core/IsolatingClassLoaderTest.java delete mode 100644 src/test/java/io/vertx/core/LauncherTest.java delete mode 100644 src/test/java/io/vertx/core/cli/AmbiguousOptionExceptionTest.java delete mode 100644 src/test/java/io/vertx/core/cli/OptionTest.java delete mode 100644 src/test/java/io/vertx/core/cli/converters/BooleanConverterTest.java delete mode 100644 src/test/java/io/vertx/core/cli/converters/CharacterConverterTest.java delete mode 100644 src/test/java/io/vertx/core/cli/converters/ConstructorBasedConverterTest.java delete mode 100644 src/test/java/io/vertx/core/cli/converters/ConvertersTest.java delete mode 100644 src/test/java/io/vertx/core/cli/converters/CustomConverterTest.java delete mode 100644 src/test/java/io/vertx/core/cli/converters/Person.java delete mode 100644 src/test/java/io/vertx/core/cli/converters/Person2.java delete mode 100644 src/test/java/io/vertx/core/cli/converters/Person3.java delete mode 100644 src/test/java/io/vertx/core/cli/converters/Person4.java delete mode 100644 src/test/java/io/vertx/core/cli/converters/Person4Converter.java delete mode 100644 src/test/java/io/vertx/core/cli/impl/CLIConfiguratorTest.java delete mode 100644 src/test/java/io/vertx/core/cli/impl/DefaultCLITest.java delete mode 100644 src/test/java/io/vertx/core/cli/impl/DefaultParserTest.java delete mode 100644 src/test/java/io/vertx/core/cli/impl/HelloClI.java delete mode 100644 src/test/java/io/vertx/core/cli/impl/IntensiveDefaultParserTest.java delete mode 100644 src/test/java/io/vertx/core/cli/impl/TypedArgumentTest.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/DefaultCommandTest.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/LauncherExtensibilityTest.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/ServiceCommandLoaderTest.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/VertxCommandLineInterfaceTest.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/BareCommandTest.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/ClasspathHandlerTest.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/CommandTestBase.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/ComplexCommand.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/ComplexCommandFactory.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/ExecUtilsTest.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/FileSelectorTest.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/GoodByeCommand.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/GoodByeCommandFactory.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/Hello2Command.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/Hello2CommandFactory.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/HelloCommand.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/HelloCommandFactory.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/HiddenCommand.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/HiddenCommandFactory.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/HttpTestVerticle.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/OptionsRecordingLauncher.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/PriorityCommandTest.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/RedeployTest.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/RunCommandTest.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/ServiceCommandLookupTest.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/StartStopListCommandsTest.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/WatcherAbsolutePathTest.java delete mode 100644 src/test/java/io/vertx/core/impl/launcher/commands/WatcherTest.java delete mode 100644 src/test/resources/META-INF/MANIFEST-Launcher-Default-Command.MF delete mode 100644 src/test/resources/META-INF/MANIFEST-Launcher-Http-Verticle.MF delete mode 100644 src/test/resources/META-INF/MANIFEST-Launcher-Missing-Main-Verticle.MF delete mode 100644 src/test/resources/META-INF/MANIFEST-Launcher-No-Main-Verticle.MF delete mode 100644 src/test/resources/META-INF/MANIFEST-Launcher-hello.MF delete mode 100644 src/test/resources/META-INF/MANIFEST-Launcher-run.MF delete mode 100644 src/test/resources/META-INF/MANIFEST-Launcher.MF diff --git a/src/main/generated/io/vertx/core/cli/ArgumentConverter.java b/src/main/generated/io/vertx/core/cli/ArgumentConverter.java deleted file mode 100644 index 7ba919378a8..00000000000 --- a/src/main/generated/io/vertx/core/cli/ArgumentConverter.java +++ /dev/null @@ -1,81 +0,0 @@ -package io.vertx.core.cli; - -import io.vertx.core.json.JsonObject; -import io.vertx.core.json.JsonArray; -import io.vertx.core.json.impl.JsonUtil; -import java.time.Instant; -import java.time.format.DateTimeFormatter; -import java.util.Base64; - -/** - * Converter and mapper for {@link io.vertx.core.cli.Argument}. - * NOTE: This class has been automatically generated from the {@link io.vertx.core.cli.Argument} original class using Vert.x codegen. - */ -public class ArgumentConverter { - - - private static final Base64.Decoder BASE64_DECODER = JsonUtil.BASE64_DECODER; - private static final Base64.Encoder BASE64_ENCODER = JsonUtil.BASE64_ENCODER; - - static void fromJson(Iterable> json, Argument obj) { - for (java.util.Map.Entry member : json) { - switch (member.getKey()) { - case "argName": - if (member.getValue() instanceof String) { - obj.setArgName((String)member.getValue()); - } - break; - case "defaultValue": - if (member.getValue() instanceof String) { - obj.setDefaultValue((String)member.getValue()); - } - break; - case "description": - if (member.getValue() instanceof String) { - obj.setDescription((String)member.getValue()); - } - break; - case "hidden": - if (member.getValue() instanceof Boolean) { - obj.setHidden((Boolean)member.getValue()); - } - break; - case "index": - if (member.getValue() instanceof Number) { - obj.setIndex(((Number)member.getValue()).intValue()); - } - break; - case "multiValued": - if (member.getValue() instanceof Boolean) { - obj.setMultiValued((Boolean)member.getValue()); - } - break; - case "required": - if (member.getValue() instanceof Boolean) { - obj.setRequired((Boolean)member.getValue()); - } - break; - } - } - } - - static void toJson(Argument obj, JsonObject json) { - toJson(obj, json.getMap()); - } - - static void toJson(Argument obj, java.util.Map json) { - if (obj.getArgName() != null) { - json.put("argName", obj.getArgName()); - } - if (obj.getDefaultValue() != null) { - json.put("defaultValue", obj.getDefaultValue()); - } - if (obj.getDescription() != null) { - json.put("description", obj.getDescription()); - } - json.put("hidden", obj.isHidden()); - json.put("index", obj.getIndex()); - json.put("multiValued", obj.isMultiValued()); - json.put("required", obj.isRequired()); - } -} diff --git a/src/main/generated/io/vertx/core/cli/OptionConverter.java b/src/main/generated/io/vertx/core/cli/OptionConverter.java deleted file mode 100644 index ad97d29e9e1..00000000000 --- a/src/main/generated/io/vertx/core/cli/OptionConverter.java +++ /dev/null @@ -1,129 +0,0 @@ -package io.vertx.core.cli; - -import io.vertx.core.json.JsonObject; -import io.vertx.core.json.JsonArray; -import io.vertx.core.json.impl.JsonUtil; -import java.time.Instant; -import java.time.format.DateTimeFormatter; -import java.util.Base64; - -/** - * Converter and mapper for {@link io.vertx.core.cli.Option}. - * NOTE: This class has been automatically generated from the {@link io.vertx.core.cli.Option} original class using Vert.x codegen. - */ -public class OptionConverter { - - - private static final Base64.Decoder BASE64_DECODER = JsonUtil.BASE64_DECODER; - private static final Base64.Encoder BASE64_ENCODER = JsonUtil.BASE64_ENCODER; - - static void fromJson(Iterable> json, Option obj) { - for (java.util.Map.Entry member : json) { - switch (member.getKey()) { - case "argName": - if (member.getValue() instanceof String) { - obj.setArgName((String)member.getValue()); - } - break; - case "choices": - if (member.getValue() instanceof JsonArray) { - java.util.LinkedHashSet list = new java.util.LinkedHashSet<>(); - ((Iterable)member.getValue()).forEach( item -> { - if (item instanceof String) - list.add((String)item); - }); - obj.setChoices(list); - } - break; - case "defaultValue": - if (member.getValue() instanceof String) { - obj.setDefaultValue((String)member.getValue()); - } - break; - case "description": - if (member.getValue() instanceof String) { - obj.setDescription((String)member.getValue()); - } - break; - case "flag": - if (member.getValue() instanceof Boolean) { - obj.setFlag((Boolean)member.getValue()); - } - break; - case "help": - if (member.getValue() instanceof Boolean) { - obj.setHelp((Boolean)member.getValue()); - } - break; - case "hidden": - if (member.getValue() instanceof Boolean) { - obj.setHidden((Boolean)member.getValue()); - } - break; - case "longName": - if (member.getValue() instanceof String) { - obj.setLongName((String)member.getValue()); - } - break; - case "multiValued": - if (member.getValue() instanceof Boolean) { - obj.setMultiValued((Boolean)member.getValue()); - } - break; - case "name": - break; - case "required": - if (member.getValue() instanceof Boolean) { - obj.setRequired((Boolean)member.getValue()); - } - break; - case "shortName": - if (member.getValue() instanceof String) { - obj.setShortName((String)member.getValue()); - } - break; - case "singleValued": - if (member.getValue() instanceof Boolean) { - obj.setSingleValued((Boolean)member.getValue()); - } - break; - } - } - } - - static void toJson(Option obj, JsonObject json) { - toJson(obj, json.getMap()); - } - - static void toJson(Option obj, java.util.Map json) { - if (obj.getArgName() != null) { - json.put("argName", obj.getArgName()); - } - if (obj.getChoices() != null) { - JsonArray array = new JsonArray(); - obj.getChoices().forEach(item -> array.add(item)); - json.put("choices", array); - } - if (obj.getDefaultValue() != null) { - json.put("defaultValue", obj.getDefaultValue()); - } - if (obj.getDescription() != null) { - json.put("description", obj.getDescription()); - } - json.put("flag", obj.isFlag()); - json.put("help", obj.isHelp()); - json.put("hidden", obj.isHidden()); - if (obj.getLongName() != null) { - json.put("longName", obj.getLongName()); - } - json.put("multiValued", obj.isMultiValued()); - if (obj.getName() != null) { - json.put("name", obj.getName()); - } - json.put("required", obj.isRequired()); - if (obj.getShortName() != null) { - json.put("shortName", obj.getShortName()); - } - json.put("singleValued", obj.isSingleValued()); - } -} diff --git a/src/main/java/io/vertx/core/AbstractVerticle.java b/src/main/java/io/vertx/core/AbstractVerticle.java index 6de46988681..21e9ac4a82b 100644 --- a/src/main/java/io/vertx/core/AbstractVerticle.java +++ b/src/main/java/io/vertx/core/AbstractVerticle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2019 Contributors to the Eclipse Foundation + * Copyright (c) 2011-2023 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 @@ -13,6 +13,7 @@ import io.vertx.core.json.JsonObject; +import java.util.Collections; import java.util.List; /** @@ -87,10 +88,13 @@ public JsonObject config() { /** * Get the arguments used when deploying the Vert.x process. + * * @return the list of arguments + * @deprecated As of version 5, Vert.x is no longer tightly coupled to the CLI */ + @Deprecated public List processArgs() { - return context.processArgs(); + return Collections.emptyList(); } /** diff --git a/src/main/java/io/vertx/core/Context.java b/src/main/java/io/vertx/core/Context.java index 38784cfe202..c41bb3a49a9 100644 --- a/src/main/java/io/vertx/core/Context.java +++ b/src/main/java/io/vertx/core/Context.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2019 Contributors to the Eclipse Foundation + * Copyright (c) 2011-2023 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 @@ -16,9 +16,9 @@ import io.vertx.codegen.annotations.Nullable; import io.vertx.codegen.annotations.VertxGen; import io.vertx.core.impl.VertxThread; -import io.vertx.core.impl.launcher.VertxCommandLauncher; import io.vertx.core.json.JsonObject; +import java.util.Collections; import java.util.List; import java.util.concurrent.Callable; @@ -46,10 +46,10 @@ * of the verticle. *

* This means (in the case of a standard verticle) that the verticle code will always be executed with the exact same - * thread, so you don't have to worry about multi-threaded acccess to the verticle state and you can code your application + * thread, so you don't have to worry about multithreaded acccess to the verticle state, and you can code your application * as single threaded. *

- * This class also allows arbitrary data to be {@link #put} and {@link #get} on the context so it can be shared easily + * This class also allows arbitrary data to be {@link #put} and {@link #get} on the context, so it can be shared easily * amongst different handlers of, for example, a verticle instance. *

* This class also provides {@link #runOnContext} which allows an action to be executed asynchronously using the same context. @@ -109,7 +109,7 @@ static boolean isOnVertxThread() { * The returned future will be completed with the result on the original context (i.e. on the original event loop of the caller) * or failed when the handler throws an exception. *

- * The blocking code should block for a reasonable amount of time (i.e no more than a few seconds). Long blocking operations + * The blocking code should block for a reasonable amount of time (i.e. no more than a few seconds). Long blocking operations * or polling operations (i.e a thread that spin in a loop polling events in a blocking fashion) are precluded. *

* When the blocking operation lasts more than the 10 seconds, a message will be printed on the console by the @@ -155,10 +155,11 @@ static boolean isOnVertxThread() { @Nullable JsonObject config(); /** - * The process args + * @deprecated As of version 5, Vert.x is no longer tightly coupled to the CLI */ + @Deprecated default List processArgs() { - return VertxCommandLauncher.getProcessArguments(); + return Collections.emptyList(); } /** @@ -168,7 +169,7 @@ default List processArgs() { * standard (not worker) verticle, the context will still an event loop context and this {@link this#isEventLoopContext()} * will return true. * - * @return true if false otherwise + * @return {@code true} if the current context is an event-loop context, {@code false} otherwise */ boolean isEventLoopContext(); @@ -179,7 +180,7 @@ default List processArgs() { * standard (not worker) verticle, the context will still an event loop context and this {@link this#isWorkerContext()} * will return false. * - * @return true if the current context is a worker context, false otherwise + * @return {@code true} if the current context is a worker context, {@code false} otherwise */ boolean isWorkerContext(); diff --git a/src/main/java/io/vertx/core/Launcher.java b/src/main/java/io/vertx/core/Launcher.java deleted file mode 100644 index e8b7f78c242..00000000000 --- a/src/main/java/io/vertx/core/Launcher.java +++ /dev/null @@ -1,116 +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.impl.launcher.VertxLifecycleHooks; -import io.vertx.core.json.JsonObject; - - -/** - * A {@code main()} class that can be used to create Vert.x instance and deploy a verticle, or run a bare Vert.x instance. - *

- * This class is used by the {@code vertx} command line utility to deploy verticles from the command line. - * It is extensible as "commands" can be added using the {@link io.vertx.core.spi.launcher.CommandFactory} - * SPI. - *

- * E.g. - *

- * {@code vertx run myverticle.js} - * {@code vertx my-command ...} - *

- * It can also be used as the main class of an executable jar so you can run verticles directly with: - *

- * {@code java -jar myapp.jar} - * - * @author Clement Escoffier - */ -public class Launcher extends VertxCommandLauncher implements VertxLifecycleHooks { - - /** - * Main entry point. - * - * @param args the user command line arguments. - */ - public static void main(String[] args) { - new Launcher().dispatch(args); - } - - /** - * Utility method to execute a specific command. - * - * @param cmd the command - * @param args the arguments - */ - public static void executeCommand(String cmd, String... args) { - new Launcher().execute(cmd, args); - } - - /** - * Hook for sub-classes of {@link Launcher} after the config has been parsed. - * - * @param config the read config, empty if none are provided. - */ - public void afterConfigParsed(JsonObject config) { - } - - /** - * Hook for sub-classes of {@link Launcher} before the vertx instance is started. - * - * @param options the configured Vert.x options. Modify them to customize the Vert.x instance. - */ - public void beforeStartingVertx(VertxOptions options) { - - } - - /** - * Hook for sub-classes of {@link Launcher} after the vertx instance is started. - * - * @param vertx the created Vert.x instance - */ - public void afterStartingVertx(Vertx vertx) { - - } - - /** - * Hook for sub-classes of {@link Launcher} before the verticle is deployed. - * - * @param deploymentOptions the current deployment options. Modify them to customize the deployment. - */ - public void beforeDeployingVerticle(DeploymentOptions deploymentOptions) { - - } - - @Override - public void beforeStoppingVertx(Vertx vertx) { - - } - - @Override - public void afterStoppingVertx() { - - } - - /** - * A deployment failure has been encountered. You can override this method to customize the behavior. - * By default it closes the `vertx` instance. - * - * @param vertx the vert.x instance - * @param mainVerticle the verticle - * @param deploymentOptions the verticle deployment options - * @param cause the cause of the failure - */ - public void handleDeployFailed(Vertx vertx, String mainVerticle, DeploymentOptions deploymentOptions, Throwable cause) { - // Default behaviour is to close Vert.x if the deploy failed - vertx.close(); - } -} diff --git a/src/main/java/io/vertx/core/cli/AmbiguousOptionException.java b/src/main/java/io/vertx/core/cli/AmbiguousOptionException.java deleted file mode 100644 index 22b81b6531d..00000000000 --- a/src/main/java/io/vertx/core/cli/AmbiguousOptionException.java +++ /dev/null @@ -1,55 +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.cli; - - -import java.util.List; -import java.util.stream.Collectors; - -/** - * Exception thrown when the command line is ambiguous meaning it cannot determine exactly which option has to be set. - * - * @author Clement Escoffier - */ -public class AmbiguousOptionException extends CLIException { - - private final List

- * If the configuration is not valid, this method throws a {@link IllegalArgumentException}. - */ - public void ensureValidity() { - if (index < 0) { - throw new IllegalArgumentException("The index cannot be negative"); - } - } - -} diff --git a/src/main/java/io/vertx/core/cli/CLI.java b/src/main/java/io/vertx/core/cli/CLI.java deleted file mode 100644 index b52669487fb..00000000000 --- a/src/main/java/io/vertx/core/cli/CLI.java +++ /dev/null @@ -1,284 +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.cli; - -import io.vertx.codegen.annotations.Fluent; -import io.vertx.codegen.annotations.GenIgnore; -import io.vertx.codegen.annotations.Nullable; -import io.vertx.codegen.annotations.VertxGen; -import io.vertx.core.cli.annotations.CLIConfigurator; -import io.vertx.core.cli.impl.DefaultCLI; - -import java.util.List; - -/** - * Interface defining a command-line interface (in other words a command such as 'run', 'ls'...). - * This interface is polyglot to ease reuse such as in Vert.x Shell. - *

- * A command line interface has a name, and defines a set of options and arguments. Options are key-value pair such - * as {@code -foo=bar} or {@code -flag}. The supported formats depend on the used parser. Arguments are unlike - * options raw values. Options are defined using - * {@link Option}, while argument are defined using {@link Argument}. - *

- * Command line interfaces also define a summary and a description. These attributes are used in the usage generation - * . To disable the help generation, set the {@code hidden} attribute to {@code true}. - *

- * Command Line Interface object does not contains "value", it's a model. It must be evaluated by a - * parser that returns a {@link CommandLine} object containing the argument and option values. - * - * @author Clement Escoffier - * @see Argument - * @see Option - */ -@VertxGen -public interface CLI { - - /** - * Creates an instance of {@link CLI} using the default implementation. - * - * @param name the name of the CLI (must not be {@code null}) - * @return the created instance of {@link CLI} - */ - static CLI create(String name) { - return new DefaultCLI().setName(name); - } - - /** - * Creates an instance of {@link CLI} from the given Java class. It instantiates the {@link CLI} object from the - * annotations used in the class. - * - * @param clazz the annotated class - * @return the created instance of {@link CLI} - */ - @GenIgnore - static CLI create(Class clazz) { - return CLIConfigurator.define(clazz); - } - - /** - * Parses the user command line interface and create a new {@link CommandLine} containing extracting values. - * - * @param arguments the arguments - * @return the creates command line - */ - CommandLine parse(List arguments); - - /** - * Parses the user command line interface and create a new {@link CommandLine} containing extracting values. - * - * @param arguments the arguments - * @param validate enable / disable parsing validation - * @return the creates command line - */ - CommandLine parse(List arguments, boolean validate); - - /** - * @return the CLI name. - */ - String getName(); - - /** - * Sets the name of the CLI. - * - * @param name the name - * @return the current {@link CLI} instance - */ - @Fluent - CLI setName(String name); - - /** - * @return the CLI description. - */ - @Nullable String getDescription(); - - @Fluent - CLI setDescription(String desc); - - /** - * @return the CLI summary. - */ - @Nullable String getSummary(); - - /** - * Sets the summary of the CLI. - * - * @param summary the summary - * @return the current {@link CLI} instance - */ - @Fluent - CLI setSummary(String summary); - - /** - * Checks whether or not the current {@link CLI} instance is hidden. - * - * @return {@code true} if the current {@link CLI} is hidden, {@link false} otherwise - */ - boolean isHidden(); - - /** - * Sets whether or not the current instance of {@link CLI} must be hidden. Hidden CLI are not listed when - * displaying usages / help messages. In other words, hidden commands are for power user. - * - * @param hidden enables or disables the hidden aspect of the CI - * @return the current {@link CLI} instance - */ - @Fluent - CLI setHidden(boolean hidden); - - /** - * Gets the list of options. - * - * @return the list of options, empty if none. - */ - List

- * Calling this method an a non-flag option throws an {@link IllegalStateException}. - * - * @param name the option name - * @return {@code true} if the flag has been set in the command line, {@code false} otherwise. - */ - boolean isFlagEnabled(String name); - - /** - * Checks whether or not the given option has been assigned in the command line. - * - * @param option the option - * @return {@code true} if the option has received a value, {@link false} otherwise. - */ - boolean isOptionAssigned(Option option); - - /** - * Gets the raw values of the given option. Raw values are simple "String", not converted to the option type. - * - * @param option the option - * @return the list of values, empty if none - * @deprecated use {@link #getRawValuesForOption(Option)} - */ - @Deprecated - default List getRawValues(Option option) { - return getRawValuesForOption(option); - } - - /** - * Gets the raw values of the given option. Raw values are simple "String", not converted to the option type. - * - * @param option the option - * @return the list of values, empty if none - */ - List getRawValuesForOption(Option option); - - /** - * Gets the raw values of the given argument. Raw values are simple "String", not converted to the argument type. - * - * @param argument the argument - * @return the list of values, empty if none - */ - List getRawValuesForArgument(Argument argument); - - /** - * Gets the raw value of the given option. Raw values are the values as given in the user command line. - * - * @param option the option - * @return the value, {@code null} if none. - */ - @Nullable String getRawValueForOption(Option option); - - /** - * Checks whether or not the given option accept more values. - * - * @param option the option - * @return {@link true} if the option accepts more values, {@link false} otherwise. - */ - boolean acceptMoreValues(Option option); - - /** - * Gets the raw value of the given argument. Raw values are the values as given in the user command line. - * - * @param arg the argument - * @return the value, {@code null} if none. - */ - @Nullable String getRawValueForArgument(Argument arg); - - /** - * Checks whether or not the given argument has been assigned in the command line. - * - * @param arg the argument - * @return {@code true} if the argument has received a value, {@link false} otherwise. - */ - boolean isArgumentAssigned(Argument arg); - - /** - * Checks whether or not the given option has been seen in the user command line. - * - * @param option the option - * @return {@code true} if the user command line has used the option - */ - boolean isSeenInCommandLine(Option option); - - /** - * Checks whether or not the command line is valid, i.e. all constraints from arguments and options have been - * satisfied. This method is used when the parser validation is disabled. - * - * @return {@code true} if the current {@link CommandLine} object is valid. {@link false} otherwise. - */ - boolean isValid(); - - /** - * Checks whether or not the user has passed a "help" option and is asking for help. - * - * @return {@code true} if the user command line has enabled a "Help" option, {@link false} otherwise. - */ - boolean isAskingForHelp(); -} diff --git a/src/main/java/io/vertx/core/cli/InvalidValueException.java b/src/main/java/io/vertx/core/cli/InvalidValueException.java deleted file mode 100644 index 4ab7a1d4e5f..00000000000 --- a/src/main/java/io/vertx/core/cli/InvalidValueException.java +++ /dev/null @@ -1,87 +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.cli; - -/** - * Exception thrown when an option or an argument receives an invalid value. - * - * @author Clement Escoffier - */ -public class InvalidValueException extends CLIException { - private final Option option; - private final Argument argument; - private final String value; - - /** - * Creates a new instance of {@link InvalidValueException} for the given option and the given value. This - * constructor is used when the option receives a value while it does not accept another value. - * - * @param option the option - * @param value the value - */ - public InvalidValueException(Option option, String value) { - this(option, value, null); - } - - - /** - * Creates a new instance of {@link InvalidValueException} for the given argument and the given value. This - * constructor is used when the argument receives a value that cannot be "converted" to the desired type. - * - * @param argument the argument - * @param value the value - * @param cause the cause - */ - public InvalidValueException(Argument argument, String value, Exception cause) { - super("The value '" + value + "' is not accepted by the argument '" - + (argument.getArgName() != null ? argument.getArgName() : argument.getIndex()) + "'", cause); - this.option = null; - this.value = value; - this.argument = argument; - } - - /** - * Creates a new instance of {@link InvalidValueException} for the given option and the given value. This - * constructor is used when the options receives a value that cannot be "converted" to the desired type. - * - * @param option the option - * @param value the value - * @param cause the cause - */ - public InvalidValueException(Option option, String value, Exception cause) { - super("The value '" + value + "' is not accepted by '" + option.getName() + "'", cause); - this.argument = null; - this.value = value; - this.option = option; - } - - /** - * @return the option, may be {@code null} if the exception is about an argument. - */ - public Option getOption() { - return option; - } - - /** - * @return the invalid value. - */ - public String getValue() { - return value; - } - - /** - * @return the argument, may be {@code null} if the exception is about an option. - */ - public Argument getArgument() { - return argument; - } -} diff --git a/src/main/java/io/vertx/core/cli/MissingOptionException.java b/src/main/java/io/vertx/core/cli/MissingOptionException.java deleted file mode 100644 index b0329b7e299..00000000000 --- a/src/main/java/io/vertx/core/cli/MissingOptionException.java +++ /dev/null @@ -1,45 +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.cli; - -import java.util.Collection; -import java.util.stream.Collectors; - -/** - * Exception thrown when an option was expected and was not found on the command line. - * - * @author Clement Escoffier - */ -public class MissingOptionException extends CLIException { - private final Collection

- * Short name is generally used with a single dash, while long name requires a double-dash. - * - * @author Clement Escoffier - */ -@DataObject(generateConverter = true, publicConverter = false) -public class Option { - - /** - * Default name in the usage message. - */ - public static final String DEFAULT_ARG_NAME = "value"; - - /** - * The default long name / short name of the option. Notice that options requires at least a regular long name or - * short name. - */ - public static final String NO_NAME = "\0"; - - /** - * the option long name. - */ - protected String longName = NO_NAME; - - /** - * the option short name. - */ - protected String shortName = NO_NAME; - - /** - * the option name used in usage message. - */ - protected String argName = DEFAULT_ARG_NAME; - - /** - * The option description. - */ - protected String description; - - /** - * whether or not the option is required. A mandatory not set throws a {@link MissingOptionException}. - */ - protected boolean required; - - /** - * whether or not the option is hidden. Hidden options are not displayed in usage. - */ - protected boolean hidden; - - /** - * whether or not the option receives a single value. {@code true} by default. - */ - protected boolean singleValued = true; - - /** - * whether or not the option can recevie multiple values. - */ - protected boolean multiValued; - - /** - * the option default value. - */ - protected String defaultValue; - - /** - * whether or not the option is a flag. Flag option does not require a value. If an option is a flag, it is - * evaluated to {@link true} if the option is used in the command line. - */ - protected boolean flag; - - /** - * whether or not the option is a "help" option. Is the user execute the command line enabling a help option, the - * command line validation won't fail, and give the command the opportunity to display the usage message, instead - * of throwing an exception during the parsing. - */ - protected boolean help; - - /** - * if the option value has to be in a definited set, this field represents the set of values. Value are sorted - * alphabetically. - */ - protected Set choices = new TreeSet<>(); - - /** - * Creates a new empty instance of {@link Option}. - */ - public Option() { - } - - /** - * Creates a new instance of {@link Option} by copying the state of another {@link Option}. - * - * @param other the other option - */ - public Option(Option other) { - this(); - this.longName = other.longName; - this.shortName = other.shortName; - this.argName = other.argName; - this.description = other.description; - this.required = other.required; - this.hidden = other.hidden; - this.singleValued = other.singleValued; - this.multiValued = other.multiValued; - this.defaultValue = other.defaultValue; - this.flag = other.flag; - this.help = other.help; - this.choices = other.choices; - } - - /** - * Creates a new instance of {@link Option} from the given {@link JsonObject} - * - * @param json the json object representing the option - * @see #toJson() - */ - public Option(JsonObject json) { - this(); - OptionConverter.fromJson(json, this); - } - - /** - * Gets the json representation of this {@link Option}. - * - * @return the json representation - */ - public JsonObject toJson() { - JsonObject json = new JsonObject(); - OptionConverter.toJson(this, json); - return json; - } - - /** - * Checks whether or not the option is valid. This implementation check that it has a short name or a long name. - * This method is intended to be extended by sub-class. Parser should check that the set of - * option of a {@link CLI} is valid before starting the parsing. - *

- * If the configuration is not valid, this method throws a {@link IllegalArgumentException}. - */ - public void ensureValidity() { - if ((shortName == null || shortName.equals(NO_NAME)) && (longName == null || longName.equals(NO_NAME))) { - throw new IllegalArgumentException("An option needs at least a long name or a short name"); - } - } - - /** - * @return whether or not the option can receive a value. - */ - public boolean acceptValue() { - return singleValued || multiValued; - } - - /** - * @return the option name. It returns the long name if set, the short name otherwise. It cannot return {@code - * null} for valid option - * @see #ensureValidity() - */ - public String getName() { - if (longName != null && !longName.equals(NO_NAME)) { - return longName; - } - // So by validity, it necessarily has a short name. - return shortName; - } - - /** - * @return whether or not this option can receive several values. - */ - public boolean isMultiValued() { - return multiValued; - } - - /** - * Sets whether or not this option can receive several values. - * - * @param multiValued whether or not this option is multi-valued. - * @return the current {@link Option} instance - */ - public Option setMultiValued(boolean multiValued) { - this.multiValued = multiValued; - if (this.multiValued) { - // If we accept more than one, we also accept 1. - this.singleValued = true; - } - // Else we cannot say what is the desired value of singleValued, it needs to be explicitly set. - return this; - } - - /** - * @return whether or not this option is single valued. - */ - public boolean isSingleValued() { - return singleValued; - } - - /** - * Sets whether or not this option can receive a value. - * - * @param singleValued whether or not this option is single-valued. - * @return the current {@link Option} instance - */ - public Option setSingleValued(boolean singleValued) { - this.singleValued = singleValued; - return this; - } - - /** - * @return the option arg name used in usage messages, {@code null} if not set. - */ - public String getArgName() { - return argName; - } - - /** - * Sets te arg name for this option. - * - * @param argName the arg name, must not be {@code null} - * @return the current {@link Option} instance - */ - public Option setArgName(String argName) { - Objects.requireNonNull(argName); - this.argName = argName; - return this; - } - - /** - * @return the description of this option, {@code null} if not set. - */ - public String getDescription() { - return description; - } - - /** - * Sets te description of this option. - * - * @param description the description - * @return the current {@link Option} instance - */ - public Option setDescription(String description) { - this.description = description; - return this; - } - - /** - * @return whtehr or not this option is hidden. - */ - public boolean isHidden() { - return hidden; - } - - /** - * Sets whether or not this option should be hidden - * - * @param hidden {@code true} to make this option hidden, {@link false} otherwise - * @return the current {@link Option} instance - */ - public Option setHidden(boolean hidden) { - this.hidden = hidden; - return this; - } - - /** - * @return the option long name, {@code null} if not set. - */ - public String getLongName() { - return longName; - } - - /** - * Sets the long name of this option. - * - * @param longName the long name - * @return the current {@link Option} instance - */ - public Option setLongName(String longName) { - this.longName = longName; - return this; - } - - /** - * @return whether or not this option is mandatory. - */ - public boolean isRequired() { - return required; - } - - /** - * Sets whether or not this option is mandatory. - * - * @param required {@code true} to make this option mandatory, {@link false} otherwise - * @return the current {@link Option} instance - */ - public Option setRequired(boolean required) { - this.required = required; - return this; - } - - /** - * @return the short name of this option, {@code null} if not set. - */ - public String getShortName() { - return shortName; - } - - /** - * Sets the short name of this option. - * - * @param shortName the short name - * @return the current {@link Option} instance - */ - public Option setShortName(String shortName) { - this.shortName = shortName; - return this; - } - - /** - * @return the default value of this option, {@code null} if not set. - */ - public String getDefaultValue() { - return defaultValue; - } - - /** - * Sets the default value of this option - * - * @param defaultValue the default value - * @return the current {@link Option} instance - */ - public Option setDefaultValue(String defaultValue) { - this.defaultValue = defaultValue; - if (this.defaultValue != null) { - setRequired(false); - } - return this; - } - - /** - * @return whether or not this option is a flag. - */ - public boolean isFlag() { - return flag; - } - - /** - * Configures the current {@link Option} to be a flag. It will be evaluated to {@code true} if it's found in - * the command line. If you need a flag that may receive a value, use, in this order: - *

-   *   option.setFlag(true).setSingleValued(true)
-   * 
- * - * @param flag whether or not the option is a flag. - * @return the current {@link Option} - */ - public Option setFlag(boolean flag) { - this.flag = flag; - if (flag) { - setSingleValued(false); - } - return this; - } - - /** - * Checks whether or not this option is a "Help" option. - * - * @return {@code true} if this option is a "help" option. - */ - public boolean isHelp() { - return help; - } - - /** - * Sets whether or not this option is a "help" option - * - * @param help {@code true} to set this option as a "Help" option - * @return the current {@link Option} - */ - public Option setHelp(boolean help) { - this.help = help; - return this; - } - - /** - * @return get the list of choices for the given option. Empty if this option does not define choices. - */ - public Set getChoices() { - return choices; - } - - /** - * Sets the list of values accepted by this option. If the value set by the user does not match once of these - * values, a {@link InvalidValueException} exception is thrown. - * - * @param choices the choices - * @return the current {@link Option} - */ - public Option setChoices(Set choices) { - this.choices = choices; - return this; - } - - /** - * Adds a choice to the list of values accepted by this option. If the value set by the user does not match once of these - * values, a {@link InvalidValueException} exception is thrown. - * - * @param choice the choice - * @return the current {@link Option} - */ - public Option addChoice(String choice) { - this.choices.add(choice); - return this; - } -} diff --git a/src/main/java/io/vertx/core/cli/TypedArgument.java b/src/main/java/io/vertx/core/cli/TypedArgument.java deleted file mode 100644 index 25f8c16aab2..00000000000 --- a/src/main/java/io/vertx/core/cli/TypedArgument.java +++ /dev/null @@ -1,142 +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.cli; - -import io.vertx.core.cli.converters.Converter; - -/** - * An implementation of {@link Argument} for java specifying the type of object received by the argument. This - * allows converting the given raw value into the specified type. - * - * @author Clement Escoffier - */ -public class TypedArgument extends Argument { - - /** - * The type of the argument. - */ - protected Class type; - - /** - * The converter to use to create the value. - */ - protected Converter converter; - - /** - * Creates a new instance of {@link TypedArgument} by copying the state of another {@link TypedArgument}. - * - * @param arg the copied argument - */ - public TypedArgument(TypedArgument arg) { - super(arg); - this.type = arg.getType(); - this.converter = arg.getConverter(); - } - - /** - * Creates an empty instance of {@link TypedArgument}. - */ - public TypedArgument() { - super(); - } - - /** - * @return the argument type, cannot be {@code null} for valid argument. - */ - public Class getType() { - return type; - } - - /** - * Sets the argument type. - * - * @param type the type - * @return the current {@link TypedArgument} instance - */ - public TypedArgument setType(Class type) { - this.type = type; - return this; - } - - /** - * @return the converter used to create the value, {@code null} if not set - */ - public Converter getConverter() { - return converter; - } - - /** - * Sets the converter used to create the value. - * - * @param converter the converter - * @return the current {@link TypedArgument} instance - */ - public TypedArgument setConverter(Converter converter) { - this.converter = converter; - return this; - } - - /** - * Checks whether or not the argument configuration is valid. In addition of the check made by the parent class it - * ensures that the type is set. - * If the configuration is not valid, this method throws a {@link IllegalArgumentException}. - */ - @Override - public void ensureValidity() { - super.ensureValidity(); - if (type == null) { - throw new IllegalArgumentException("Type must not be null"); - } - } - - @Override - public TypedArgument setArgName(String argName) { - super.setArgName(argName); - return this; - } - - @Override - public TypedArgument setDefaultValue(String defaultValue) { - super.setDefaultValue(defaultValue); - return this; - } - - @Override - public TypedArgument setDescription(String description) { - super.setDescription(description); - return this; - } - - @Override - public TypedArgument setHidden(boolean hidden) { - super.setHidden(hidden); - return this; - } - - @Override - public TypedArgument setIndex(int index) { - super.setIndex(index); - return this; - } - - @Override - public TypedArgument setRequired(boolean required) { - super.setRequired(required); - return this; - } - - @Override - public TypedArgument setMultiValued(boolean multiValued) { - super.setMultiValued(multiValued); - return this; - } -} diff --git a/src/main/java/io/vertx/core/cli/TypedOption.java b/src/main/java/io/vertx/core/cli/TypedOption.java deleted file mode 100644 index e840f7db830..00000000000 --- a/src/main/java/io/vertx/core/cli/TypedOption.java +++ /dev/null @@ -1,200 +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.cli; - -import io.vertx.core.cli.converters.Converter; - -import java.util.Arrays; -import java.util.Objects; -import java.util.Set; - -/** - * An implementation of {@link Option} for java specifying the type of - * object received by the option. This allows converting the given raw value into the specified type. - * - * @author Clement Escoffier - */ -public class TypedOption extends Option { - - /** - * The type of the option. - */ - protected Class type; - - /** - * whether or not the raw value should be parsed as a list. The list if computed by splitting the value. - */ - protected boolean parsedAsList; - - /** - * the split character used if the raw value needs to be parsed as a list. {@code ','} is used by default. - */ - protected String listSeparator = ","; - - /** - * the converter to create the value. - */ - protected Converter converter; - - /** - * Creates an empty instance of {@link TypedOption}. - */ - public TypedOption() { - super(); - } - - /** - * Creates an instance of {@link TypedOption} by copying the state of another {@link TypedOption} - * - * @param option the copied option - */ - public TypedOption(TypedOption option) { - super(option); - this.type = option.getType(); - this.converter = option.getConverter(); - this.parsedAsList = option.isParsedAsList(); - this.listSeparator = option.getListSeparator(); - } - - @Override - public TypedOption setMultiValued(boolean acceptMultipleValues) { - super.setMultiValued(acceptMultipleValues); - return this; - } - - @Override - public TypedOption setSingleValued(boolean acceptSingleValue) { - super.setSingleValued(acceptSingleValue); - return this; - } - - @Override - public TypedOption setArgName(String argName) { - super.setArgName(argName); - return this; - } - - @Override - public TypedOption setDefaultValue(String defaultValue) { - super.setDefaultValue(defaultValue); - return this; - } - - @Override - public TypedOption setDescription(String description) { - super.setDescription(description); - return this; - } - - @Override - public TypedOption setFlag(boolean flag) { - super.setFlag(flag); - return this; - } - - @Override - public TypedOption setHidden(boolean hidden) { - super.setHidden(hidden); - return this; - } - - @Override - public TypedOption setLongName(String longName) { - super.setLongName(longName); - return this; - } - - @Override - public TypedOption setRequired(boolean required) { - super.setRequired(required); - return this; - } - - @Override - public TypedOption setShortName(String shortName) { - super.setShortName(shortName); - return this; - } - - public Class getType() { - return type; - } - - public TypedOption setType(Class type) { - this.type = type; - if (type != null && getChoices().isEmpty() && type.isEnum()) { - setChoicesFromEnumType(); - } - return this; - } - - public boolean isParsedAsList() { - return parsedAsList; - } - - public TypedOption setParsedAsList(boolean isList) { - this.parsedAsList = isList; - return this; - } - - public String getListSeparator() { - return listSeparator; - } - - public TypedOption setListSeparator(String listSeparator) { - Objects.requireNonNull(listSeparator); - this.parsedAsList = true; - this.listSeparator = listSeparator; - return this; - } - - public Converter getConverter() { - return converter; - } - - public TypedOption setConverter(Converter converter) { - this.converter = converter; - return this; - } - - @Override - public void ensureValidity() { - super.ensureValidity(); - if (type == null) { - throw new IllegalArgumentException("Type must not be null"); - } - } - - @Override - public TypedOption setChoices(Set choices) { - super.setChoices(choices); - return this; - } - - @Override - public TypedOption addChoice(String choice) { - super.addChoice(choice); - return this; - } - - /** - * Sets the list of values accepted by this option from the option's type. - */ - private void setChoicesFromEnumType() { - Object[] constants = type.getEnumConstants(); - for (Object c : constants) { - addChoice(c.toString()); - } - } - - -} diff --git a/src/main/java/io/vertx/core/cli/UsageMessageFormatter.java b/src/main/java/io/vertx/core/cli/UsageMessageFormatter.java deleted file mode 100644 index 5703d4505e8..00000000000 --- a/src/main/java/io/vertx/core/cli/UsageMessageFormatter.java +++ /dev/null @@ -1,705 +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.cli; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.StringReader; -import java.util.*; -import java.util.stream.Collectors; - - -/** - * Usage message formatter. - * - * @author Clement Escoffier - */ -public class UsageMessageFormatter { - - /** - * default number of characters per line - */ - public static final int DEFAULT_WIDTH = 80; - - /** - * default padding to the left of each line - */ - public static final int DEFAULT_LEFT_PAD = 1; - - /** - * number of space characters to be prefixed to each description line - */ - public static final int DEFAULT_DESC_PAD = 3; - - /** - * the string to display at the beginning of the usage statement - */ - public static final String DEFAULT_USAGE_PREFIX = "Usage: "; - - /** - * default prefix for shortOpts - */ - public static final String DEFAULT_OPT_PREFIX = "-"; - - /** - * default prefix for long Option - */ - public static final String DEFAULT_LONG_OPT_PREFIX = "--"; - - /** - * default separator displayed between a long Option and its value - */ - public static final String DEFAULT_LONG_OPT_SEPARATOR = " "; - - /** - * default name for an argument - */ - public static final String DEFAULT_ARG_NAME = "arg"; - - private int width = DEFAULT_WIDTH; - private int leftPad = DEFAULT_LEFT_PAD; - private int descPad = DEFAULT_DESC_PAD; - private String usagePrefix = DEFAULT_USAGE_PREFIX; - private String newLine = System.lineSeparator(); - private String defaultOptionPrefix = DEFAULT_OPT_PREFIX; - private String defaultLongOptPrefix = DEFAULT_LONG_OPT_PREFIX; - private String defaultArgName = DEFAULT_ARG_NAME; - private String longOptSeparator = DEFAULT_LONG_OPT_SEPARATOR; - - /** - * Comparator used to sort the options when they output in help text - *

- * Defaults to case-insensitive alphabetical sorting by option key. - */ - protected Comparator

- * Index is mandatory to force you to think to the order. - */ - int index(); - - /** - * Whether or not the argument is required. An argument is required by default. - */ - boolean required() default true; -} diff --git a/src/main/java/io/vertx/core/cli/annotations/CLIConfigurator.java b/src/main/java/io/vertx/core/cli/annotations/CLIConfigurator.java deleted file mode 100644 index f642265b5eb..00000000000 --- a/src/main/java/io/vertx/core/cli/annotations/CLIConfigurator.java +++ /dev/null @@ -1,277 +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.cli.annotations; - -import io.vertx.core.cli.*; -import io.vertx.core.cli.impl.DefaultCLI; -import io.vertx.core.cli.impl.ReflectionUtils; - -import java.lang.reflect.Array; -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -/** - * Class responsible for defining CLI using annotations and injecting values extracted by the parser. - * - * @author Clement Escoffier - */ -public class CLIConfigurator { - - - /** - * Creates an instance of the given class, and extracts the metadata from the given class. - * - * @param clazz the CLI class - * @return the defined CLI. - */ - public static CLI define(Class clazz) { - CLI cli = new DefaultCLI(); - - // Class annotations - final Summary summary = clazz.getAnnotation(Summary.class); - final Description desc = clazz.getAnnotation(Description.class); - final Hidden hidden = clazz.getAnnotation(Hidden.class); - final Name name = clazz.getAnnotation(Name.class); - - if (name == null) { - throw new IllegalArgumentException("The command cannot be defined, the @Name annotation is missing."); - } - if (name.value().isEmpty()) { - throw new IllegalArgumentException("The command cannot be defined, the @Name value is empty or null."); - } - cli.setName(name.value()); - cli.setPriority(name.priority()); - - if (summary != null) { - cli.setSummary(summary.value()); - } - if (desc != null) { - cli.setDescription(desc.value()); - } - if (hidden != null) { - cli.setHidden(true); - } - - // Setter annotations - final List methods = ReflectionUtils.getSetterMethods(clazz); - for (Method method : methods) { - final Option option = method.getAnnotation(Option.class); - final Argument argument = method.getAnnotation(Argument.class); - - if (option != null) { - cli.addOption(createOption(method)); - } - if (argument != null) { - cli.addArgument(createArgument(method)); - } - } - - return cli; - } - - @SuppressWarnings("unchecked") - private static io.vertx.core.cli.Option createOption(Method method) { - TypedOption opt = new TypedOption(); - - // Option - Option option = method.getAnnotation(Option.class); - opt.setLongName(option.longName()) - .setShortName(option.shortName()) - .setMultiValued(option.acceptMultipleValues()) - .setSingleValued(option.acceptValue()) - .setArgName(option.argName()) - .setFlag(option.flag()) - .setHelp(option.help()) - .setRequired(option.required()); - - // Description - Description description = method.getAnnotation(Description.class); - if (description != null) { - opt.setDescription(description.value()); - } - - Hidden hidden = method.getAnnotation(Hidden.class); - if (hidden != null) { - opt.setHidden(true); - } - - if (ReflectionUtils.isMultiple(method)) { - opt - .setType(ReflectionUtils.getComponentType(method.getParameters()[0])) - .setMultiValued(true); - } else { - final Class type = method.getParameters()[0].getType(); - opt.setType(type); - if (type != Boolean.TYPE && type != Boolean.class) { - // In the case of a boolean, it may be a flag, need explicit settings. - opt.setSingleValued(true); - } - } - - ConvertedBy convertedBy = method.getAnnotation(ConvertedBy.class); - if (convertedBy != null) { - opt.setConverter(ReflectionUtils.newInstance(convertedBy.value())); - } - ParsedAsList parsedAsList = method.getAnnotation(ParsedAsList.class); - if (parsedAsList != null) { - opt.setParsedAsList(true).setListSeparator(parsedAsList.separator()); - } - - // Default value - DefaultValue defaultValue = method.getAnnotation(DefaultValue.class); - if (defaultValue != null) { - opt.setDefaultValue(defaultValue.value()); - } - - opt.ensureValidity(); - - return opt; - } - - @SuppressWarnings("unchecked") - private static io.vertx.core.cli.Argument createArgument(Method method) { - TypedArgument arg = new TypedArgument(); - - // Argument - Argument argument = method.getAnnotation(Argument.class); - arg.setIndex(argument.index()); - arg.setArgName(argument.argName()); - arg.setRequired(argument.required()); - - // Description - Description description = method.getAnnotation(Description.class); - if (description != null) { - arg.setDescription(description.value()); - } - - if (ReflectionUtils.isMultiple(method)) { - arg - .setType(ReflectionUtils.getComponentType(method.getParameters()[0])) - .setMultiValued(true); - } else { - final Class type = method.getParameters()[0].getType(); - arg.setType(type); - } - - Hidden hidden = method.getAnnotation(Hidden.class); - if (hidden != null) { - arg.setHidden(true); - } - - ConvertedBy convertedBy = method.getAnnotation(ConvertedBy.class); - if (convertedBy != null) { - arg.setConverter(ReflectionUtils.newInstance(convertedBy.value())); - } - - // Default value - DefaultValue defaultValue = method.getAnnotation(DefaultValue.class); - if (defaultValue != null) { - arg.setDefaultValue(defaultValue.value()); - } - - return arg; - } - - private static Object getOptionValue(Method method, String name, CommandLine commandLine) { - final io.vertx.core.cli.Option option = commandLine.cli().getOption(name); - if (option == null) { - return null; - } - boolean multiple = ReflectionUtils.isMultiple(method); - if (multiple) { - return createMultiValueContainer(method, commandLine.getOptionValues(name)); - } - return commandLine.getOptionValue(name); - } - - private static Object getArgumentValue(Method method, int index, CommandLine commandLine) { - final io.vertx.core.cli.Argument argument = commandLine.cli().getArgument(index); - if (argument == null) { - return null; - } - - boolean multiple = ReflectionUtils.isMultiple(method); - if (multiple) { - return createMultiValueContainer(method, commandLine.getArgumentValues(argument.getIndex())); - } - return commandLine.getArgumentValue(argument.getIndex()); - } - - /** - * Injects the value in the annotated setter methods ({@link Option} and {@link Argument}. - * - * @param cli the cli - * @param object the object to be injected - * @throws CLIException if an injection issue occurred. - */ - public static void inject(CommandLine cli, Object object) throws CLIException { - final List methods = ReflectionUtils.getSetterMethods(object.getClass()); - for (Method method : methods) { - Option option = method.getAnnotation(Option.class); - Argument argument = method.getAnnotation(Argument.class); - if (option != null) { - String name = option.longName(); - if (name == null) { - name = option.shortName(); - } - try { - Object injected = getOptionValue(method, name, cli); - if (injected != null) { - method.setAccessible(true); - method.invoke(object, injected); - } - } catch (Exception e) { - throw new CLIException("Cannot inject value for option '" + name + "'", e); - } - } - - if (argument != null) { - int index = argument.index(); - try { - Object injected = getArgumentValue(method, index, cli); - if (injected != null) { - method.setAccessible(true); - method.invoke(object, injected); - } - } catch (Exception e) { - throw new CLIException("Cannot inject value for argument '" + index + "'", e); - } - } - - } - } - - private static Object createMultiValueContainer(Method setter, List values) { - final Class type = setter.getParameterTypes()[0]; - if (type.isArray()) { - Object array = Array.newInstance(type.getComponentType(), values.size()); - for (int i = 0; i < values.size(); i++) { - Array.set(array, i, values.get(i)); - } - return array; - } - - if (Set.class.isAssignableFrom(type)) { - return new LinkedHashSet<>(values); - } - - if (List.class.isAssignableFrom(type) || Collection.class.isAssignableFrom(type)) { - return values; - } - - return null; - } - -} diff --git a/src/main/java/io/vertx/core/cli/annotations/ConvertedBy.java b/src/main/java/io/vertx/core/cli/annotations/ConvertedBy.java deleted file mode 100644 index 62085bbf3e6..00000000000 --- a/src/main/java/io/vertx/core/cli/annotations/ConvertedBy.java +++ /dev/null @@ -1,36 +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.cli.annotations; - -import io.vertx.core.cli.converters.Converter; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates {@link Option @Option} setters to indicate how the value is converted to the argument type. - * - * @author Clement Escoffier - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD, ElementType.TYPE}) -public @interface ConvertedBy { - - /** - * The converter class used to transform the value as String to the target type. This converter is also used for - * the {@link DefaultValue}. - */ - Class> value(); - -} diff --git a/src/main/java/io/vertx/core/cli/annotations/DefaultValue.java b/src/main/java/io/vertx/core/cli/annotations/DefaultValue.java deleted file mode 100644 index 463ed2ee8fa..00000000000 --- a/src/main/java/io/vertx/core/cli/annotations/DefaultValue.java +++ /dev/null @@ -1,36 +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.cli.annotations; - -import io.vertx.core.cli.converters.Converter; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation to set a default value to an option. - * - * @author Clement Escoffier - * @see Option - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface DefaultValue { - - /** - * The (optional) default value of the option. The value is converted to the right type using the - * {@link Converter} set in {@link ConvertedBy}. - */ - String value(); -} diff --git a/src/main/java/io/vertx/core/cli/annotations/Description.java b/src/main/java/io/vertx/core/cli/annotations/Description.java deleted file mode 100644 index 227b9602e50..00000000000 --- a/src/main/java/io/vertx/core/cli/annotations/Description.java +++ /dev/null @@ -1,33 +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.cli.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation used to write the option or command documentation. - * - * @author Clement Escoffier - * @see Summary - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD, ElementType.TYPE}) -public @interface Description { - - /** - * The documentation. - */ - String value(); -} diff --git a/src/main/java/io/vertx/core/cli/annotations/Hidden.java b/src/main/java/io/vertx/core/cli/annotations/Hidden.java deleted file mode 100644 index 058218277f9..00000000000 --- a/src/main/java/io/vertx/core/cli/annotations/Hidden.java +++ /dev/null @@ -1,29 +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.cli.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates a {@link io.vertx.core.cli.CLI} and/or its {@link Option @Option} setters to hide it from the help message. - * - * @author Clement Escoffier - * @see Summary - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD, ElementType.TYPE}) -public @interface Hidden { - // Just a marker. -} diff --git a/src/main/java/io/vertx/core/cli/annotations/Name.java b/src/main/java/io/vertx/core/cli/annotations/Name.java deleted file mode 100644 index aeb4ce59ba1..00000000000 --- a/src/main/java/io/vertx/core/cli/annotations/Name.java +++ /dev/null @@ -1,40 +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.cli.annotations; - -import io.vertx.core.cli.CLI; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Defines the name of a {@link CLI}. - * - * @author Clement Escoffier - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface Name { - - /** - * The command name. - */ - String value(); - - /** - * The command priority. If more than 1 with same name are available on the classpath the one with highest priority - * replaces the existing. - */ - int priority() default 0; -} diff --git a/src/main/java/io/vertx/core/cli/annotations/Option.java b/src/main/java/io/vertx/core/cli/annotations/Option.java deleted file mode 100644 index 70b7ce40f82..00000000000 --- a/src/main/java/io/vertx/core/cli/annotations/Option.java +++ /dev/null @@ -1,84 +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.cli.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates a setter to be called with the value of a command line option. Setter have been preferred to field to - * allow validation. - *

- * The cardinality of the option is detected from the single method parameter type: arrays, list and set can receive - * several values. - * - * @author Clement Escoffier - * @see Argument - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface Option { - - String NO_NAME = "\0"; - - /** - * The name of the option (without the {@code --} prefix). - * Defaults to a name based on the setter name - */ - String longName() default NO_NAME; - - /** - * The short option name (without the {@code -} prefix). - * If not given the option has no short name. - */ - String shortName() default NO_NAME; - - /** - * The name of this argument (used in doc) - */ - String argName() default "value"; - - /** - * Whether or not the option is required. - */ - boolean required() default false; - - /** - * Whether or not the option accept a value. - * If the setter accepts an array, a list, a set, or a collection as parameter, it automatically detect it accepts - * multiple values. - */ - boolean acceptValue() default true; - - /** - * Whether or not the option accept multiple values. If the setter accepts an array, a list, a set, or a collection - * as parameter, it automatically detect it accepts multiple values. - */ - boolean acceptMultipleValues() default false; - - /** - * Whether or not the option can be used as a flag (meaning no value) - */ - boolean flag() default false; - - /** - * Whether or not this option is a "Help" option. Help options are generally flag. - */ - boolean help() default false; - - /** - * The set of choices accepted as values by this option. No need to call this methods for enums. - */ - String[] choices() default {}; -} diff --git a/src/main/java/io/vertx/core/cli/annotations/ParsedAsList.java b/src/main/java/io/vertx/core/cli/annotations/ParsedAsList.java deleted file mode 100644 index 808f31e0f94..00000000000 --- a/src/main/java/io/vertx/core/cli/annotations/ParsedAsList.java +++ /dev/null @@ -1,37 +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.cli.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates a setter to be called with the value of a command line option. The setter must also have been annotated - * with {@link Option}. - *

- * When annotated with {@link ParsedAsList}, the option value is parsed as a list. The value is split and then each - * segment is trimmed. - * - * @author Clement Escoffier - * @see Option - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface ParsedAsList { - - /** - * The separator used to split the value. {@code ,} is used by default. - */ - String separator() default ","; -} diff --git a/src/main/java/io/vertx/core/cli/annotations/Summary.java b/src/main/java/io/vertx/core/cli/annotations/Summary.java deleted file mode 100644 index f2e0743a25e..00000000000 --- a/src/main/java/io/vertx/core/cli/annotations/Summary.java +++ /dev/null @@ -1,34 +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.cli.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates a {@link io.vertx.core.cli.CLI} with summary. The summary is the main short explanation of the command. Long - * description should be written in the {@link Description}. - * - * @author Clement Escoffier - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface Summary { - - /** - * The summary. This should be a single sentence describing what the command does. - */ - String value(); - -} diff --git a/src/main/java/io/vertx/core/cli/annotations/package-info.java b/src/main/java/io/vertx/core/cli/annotations/package-info.java deleted file mode 100644 index 6137f56ee12..00000000000 --- a/src/main/java/io/vertx/core/cli/annotations/package-info.java +++ /dev/null @@ -1,12 +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.cli.annotations; diff --git a/src/main/java/io/vertx/core/cli/converters/BooleanConverter.java b/src/main/java/io/vertx/core/cli/converters/BooleanConverter.java deleted file mode 100644 index 25eee3dee4b..00000000000 --- a/src/main/java/io/vertx/core/cli/converters/BooleanConverter.java +++ /dev/null @@ -1,49 +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.cli.converters; - -import java.util.Arrays; -import java.util.List; - -/** - * A converter for boolean. This converter considered as 'true' : "true", "on", "1", - * "yes". All other values are considered as 'false' (as a consequence, 'null' is considered as 'false'). - * - * @author Clement Escoffier - */ -public final class BooleanConverter implements Converter { - - /** - * The converter. - */ - public static final BooleanConverter INSTANCE = new BooleanConverter(); - /** - * The set of values considered as 'true'. - */ - private static final List TRUE = Arrays.asList("true", "yes", "on", "1"); - - private BooleanConverter() { - // No direct instantiation - } - - /** - * Creates the boolean value from the given String. If the given String does not match one of the 'true' value, - * {@code false} is returned. - * - * @param value the value - * @return the boolean object - */ - @Override - public Boolean fromString(String value) { - return value != null && TRUE.contains(value.toLowerCase()); - } -} diff --git a/src/main/java/io/vertx/core/cli/converters/CharacterConverter.java b/src/main/java/io/vertx/core/cli/converters/CharacterConverter.java deleted file mode 100644 index 59ba6de3f0d..00000000000 --- a/src/main/java/io/vertx/core/cli/converters/CharacterConverter.java +++ /dev/null @@ -1,46 +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.cli.converters; - - -/** - * A converter for character. Unlike other primitive types, characters cannot be created using 'valueOf'. Notice that - * only input having a length of 1 can be converted to characters. Other inputs are rejected. - * - * @author Clement Escoffier - */ -public final class CharacterConverter implements Converter { - - /** - * The converter. - */ - public static final CharacterConverter INSTANCE = new CharacterConverter(); - - private CharacterConverter() { - // No direct instantiation - } - - @Override - public Character fromString(String input) throws IllegalArgumentException { - if (input == null) { - throw new NullPointerException("input must not be null"); - } - - if (input.length() != 1) { - throw new IllegalArgumentException("The input string \"" + input + "\" cannot be converted to a " + - "character. The input's length must be 1"); - } - - return input.toCharArray()[0]; - - } -} diff --git a/src/main/java/io/vertx/core/cli/converters/ConstructorBasedConverter.java b/src/main/java/io/vertx/core/cli/converters/ConstructorBasedConverter.java deleted file mode 100644 index 699d704f12b..00000000000 --- a/src/main/java/io/vertx/core/cli/converters/ConstructorBasedConverter.java +++ /dev/null @@ -1,74 +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.cli.converters; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -/** - * This 'default' converter tries to create objects using a constructor taking a single String argument. - * Be aware that implementation must also handle the case where the input is {@literal null}. - * - * @author Clement Escoffier - */ -public final class ConstructorBasedConverter implements Converter { - - private final Constructor constructor; - - private ConstructorBasedConverter(Constructor constructor) { - this.constructor = constructor; - } - - /** - * Checks whether the given class can be used by the {@link ConstructorBasedConverter} (i.e. has a constructor - * taking a single String as argument). If so, creates a new instance of converter for this type. - * - * @param clazz the class - * @return a {@link ConstructorBasedConverter} if the given class is eligible, - * {@literal null} otherwise. - */ - public static ConstructorBasedConverter getIfEligible(Class clazz) { - try { - final Constructor constructor = clazz.getConstructor(String.class); - if (!constructor.isAccessible()) { - constructor.setAccessible(true); - } - return new ConstructorBasedConverter<>(constructor); - } catch (NoSuchMethodException e) { - // The class does not have the right constructor, return null. - return null; - } - - } - - /** - * Converts the given input to an object by using the constructor approach. Notice that the constructor must - * expect receiving a {@literal null} value. - * - * @param input the input, can be {@literal null} - * @return the instance of T - * @throws IllegalArgumentException if the instance of T cannot be created from the input. - */ - @Override - public T fromString(String input) throws IllegalArgumentException { - try { - return constructor.newInstance(input); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - if (e.getCause() != null) { - throw new IllegalArgumentException(e.getCause()); - } else { - throw new IllegalArgumentException(e); - } - } - } - -} diff --git a/src/main/java/io/vertx/core/cli/converters/Converter.java b/src/main/java/io/vertx/core/cli/converters/Converter.java deleted file mode 100644 index d1f920eec51..00000000000 --- a/src/main/java/io/vertx/core/cli/converters/Converter.java +++ /dev/null @@ -1,24 +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.cli.converters; - -/** - * The converter interface to convert {@code String}s to {@code Object}s. - * - * @author Clement Escoffier - */ -@FunctionalInterface -public interface Converter { - - T fromString(String s); - -} diff --git a/src/main/java/io/vertx/core/cli/converters/Converters.java b/src/main/java/io/vertx/core/cli/converters/Converters.java deleted file mode 100644 index 8730d866319..00000000000 --- a/src/main/java/io/vertx/core/cli/converters/Converters.java +++ /dev/null @@ -1,127 +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.cli.converters; - -import java.lang.reflect.InvocationTargetException; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.NoSuchElementException; - -/** - * Entry point to the converter system. - * - * @author Clement Escoffier - */ -public class Converters { - - private static final Map, Class> PRIMITIVE_TO_WRAPPER_TYPE; - private static final Map, Converter> WELL_KNOWN_CONVERTERS; - - static { - Map, Class> primToWrap = new HashMap<>(16); - - primToWrap.put(boolean.class, Boolean.class); - primToWrap.put(byte.class, Byte.class); - primToWrap.put(char.class, Character.class); - primToWrap.put(double.class, Double.class); - primToWrap.put(float.class, Float.class); - primToWrap.put(int.class, Integer.class); - primToWrap.put(long.class, Long.class); - primToWrap.put(short.class, Short.class); - primToWrap.put(void.class, Void.class); - - PRIMITIVE_TO_WRAPPER_TYPE = Collections.unmodifiableMap(primToWrap); - - Map, Converter> wellKnown = new HashMap<>(16); - wellKnown.put(Boolean.class, BooleanConverter.INSTANCE); - wellKnown.put(Byte.class, Byte::parseByte); - wellKnown.put(Character.class, CharacterConverter.INSTANCE); - wellKnown.put(Double.class, Double::parseDouble); - wellKnown.put(Float.class, Float::parseFloat); - wellKnown.put(Integer.class, Integer::parseInt); - wellKnown.put(Long.class, Long::parseLong); - wellKnown.put(Short.class, Short::parseShort); - wellKnown.put(String.class, value -> value); - - WELL_KNOWN_CONVERTERS = Collections.unmodifiableMap(wellKnown); - } - - public static T create(Class type, String value) { - if (type.isPrimitive()) { - type = wrap(type); - } - return getConverter(type).fromString(value); - } - - public static T create(String value, Converter converter) { - return converter.fromString(value); - } - - @SuppressWarnings("unchecked") - private static Class wrap(Class type) { - Class wrapped = (Class) PRIMITIVE_TO_WRAPPER_TYPE.get(type); - return (wrapped == null) ? type : wrapped; - } - - /** - * Searches a suitable converter to convert String to the given type. - * - * @param type the target type - * @param the class - * @return the parameter converter able to creates instances of the target type from String representations. - * @throws NoSuchElementException if no converter can be found - */ - @SuppressWarnings("unchecked") - private static Converter getConverter(Class type) { - // check for well known types first - if (WELL_KNOWN_CONVERTERS.containsKey(type)) { - return (Converter) WELL_KNOWN_CONVERTERS.get(type); - } - - // None of them are there, try default converters in the following order: - // 1. constructor - // 2. valueOf - // 3. from - // 4. fromString - Converter converter = ConstructorBasedConverter.getIfEligible(type); - if (converter != null) { - return converter; - } - converter = ValueOfBasedConverter.getIfEligible(type); - if (converter != null) { - return converter; - } - converter = FromBasedConverter.getIfEligible(type); - if (converter != null) { - return converter; - } - converter = FromStringBasedConverter.getIfEligible(type); - if (converter != null) { - return converter; - } - - // running out of converters... - throw new NoSuchElementException("Cannot find a converter able to create instance of " + type.getName()); - } - - public static Converter newInstance(Class> type) throws IllegalArgumentException { - try { - return type.getDeclaredConstructor().newInstance(); - } catch (InvocationTargetException | NoSuchMethodException | InstantiationException | IllegalAccessException e) { - throw new IllegalArgumentException("Cannot create a new instance of " + type.getName() + " - it requires an " + - "public constructor without argument", e); - } - } - - -} diff --git a/src/main/java/io/vertx/core/cli/converters/FromBasedConverter.java b/src/main/java/io/vertx/core/cli/converters/FromBasedConverter.java deleted file mode 100644 index 55c11e56f72..00000000000 --- a/src/main/java/io/vertx/core/cli/converters/FromBasedConverter.java +++ /dev/null @@ -1,84 +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.cli.converters; - - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -/** - * This 'default' converter tries to create objects using a static 'from' method taking a single String argument. - * This converter is particularly convenient for builders. - * - * @param the built type. - * @author Clement Escoffier - */ -public final class FromBasedConverter implements Converter { - - public static final String FROM = "from"; - private final Method method; - private final Class clazz; - - private FromBasedConverter(Class clazz, Method method) { - this.clazz = clazz; - this.method = method; - } - - /** - * Checks whether the given class can be used by the {@link FromBasedConverter} (i.e. has a static 'from' method - * taking a single String as argument). If so, creates a new instance of converter for this type. - * - * @param clazz the class - * @return a {@link FromBasedConverter} if the given class is eligible, - * {@literal null} otherwise. - */ - public static FromBasedConverter getIfEligible(Class clazz) { - try { - final Method method = clazz.getMethod(FROM, String.class); - if (Modifier.isStatic(method.getModifiers())) { - if (!method.isAccessible()) { - method.setAccessible(true); - } - return new FromBasedConverter<>(clazz, method); - } else { - // The from method is present but it must be static. - return null; - } - } catch (NoSuchMethodException e) { - // The class does not have the right method, return null. - return null; - } - - } - - /** - * Converts the given input to an object by using the 'from' method. Notice that the method may - * receive a {@literal null} value. - * - * @param input the input, can be {@literal null} - * @return the instance of T - * @throws IllegalArgumentException if the instance of T cannot be created from the input. - */ - @Override - public T fromString(String input) throws IllegalArgumentException { - try { - return clazz.cast(method.invoke(null, input)); - } catch (IllegalAccessException | InvocationTargetException e) { - if (e.getCause() != null) { - throw new IllegalArgumentException(e.getCause()); - } else { - throw new IllegalArgumentException(e); - } - } - } -} diff --git a/src/main/java/io/vertx/core/cli/converters/FromStringBasedConverter.java b/src/main/java/io/vertx/core/cli/converters/FromStringBasedConverter.java deleted file mode 100644 index fc60177e6df..00000000000 --- a/src/main/java/io/vertx/core/cli/converters/FromStringBasedConverter.java +++ /dev/null @@ -1,84 +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.cli.converters; - - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -/** - * This 'default' converter tries to create objects using a static 'from' method taking a single String argument. - * This converter is particularly convenient for converters themselves. - * - * @author Clement Escoffier - */ -public final class FromStringBasedConverter implements Converter { - - public static final String FROM_STRING = "fromString"; - private final Method method; - private final Class clazz; - - private FromStringBasedConverter(Class clazz, Method method) { - this.clazz = clazz; - this.method = method; - } - - /** - * Checks whether the given class can be used by the {@link FromStringBasedConverter} (i.e. has a static - * 'fromString' method taking a single String as argument). If so, creates a new instance of converter for this - * type. - * - * @param clazz the class - * @return a {@link FromStringBasedConverter} if the given class is eligible, - * {@literal null} otherwise. - */ - public static FromStringBasedConverter getIfEligible(Class clazz) { - try { - final Method method = clazz.getMethod(FROM_STRING, String.class); - if (Modifier.isStatic(method.getModifiers())) { - if (!method.isAccessible()) { - method.setAccessible(true); - } - return new FromStringBasedConverter<>(clazz, method); - } else { - // The from method is present but it must be static. - return null; - } - } catch (NoSuchMethodException e) { - // The class does not have the right method, return null. - return null; - } - - } - - /** - * Converts the given input to an object by using the 'fromString' method. Notice that the method may - * receive a {@literal null} value. - * - * @param input the input, can be {@literal null} - * @return the instance of T - * @throws IllegalArgumentException if the instance of T cannot be created from the input. - */ - @Override - public T fromString(String input) throws IllegalArgumentException { - try { - return clazz.cast(method.invoke(null, input)); - } catch (IllegalAccessException | InvocationTargetException e) { - if (e.getCause() != null) { - throw new IllegalArgumentException(e.getCause()); - } else { - throw new IllegalArgumentException(e); - } - } - } -} diff --git a/src/main/java/io/vertx/core/cli/converters/ValueOfBasedConverter.java b/src/main/java/io/vertx/core/cli/converters/ValueOfBasedConverter.java deleted file mode 100644 index 6221732aa72..00000000000 --- a/src/main/java/io/vertx/core/cli/converters/ValueOfBasedConverter.java +++ /dev/null @@ -1,83 +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.cli.converters; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -/** - * This 'default' converter tries to create objects using a static 'valueOf' method taking a single String argument. - * This converter is particularly convenient to for enumeration and primitive types. - * - * @author Clement Escoffier - */ -public final class ValueOfBasedConverter implements Converter { - - public static final String VALUE_OF = "valueOf"; - private final Method method; - private final Class clazz; - - private ValueOfBasedConverter(Class clazz, Method method) { - this.clazz = clazz; - this.method = method; - } - - /** - * Checks whether the given class can be used by the {@link ValueOfBasedConverter} (i.e. has a static 'valueOf' - * method taking a single String as argument). If so, creates a new instance of converter for this type. - * - * @param clazz the class - * @return a {@link ValueOfBasedConverter} if the given class is eligible, - * {@literal null} otherwise. - */ - @SuppressWarnings("unchecked") - public static ValueOfBasedConverter getIfEligible(Class clazz) { - try { - final Method method = clazz.getMethod(VALUE_OF, String.class); - if (Modifier.isStatic(method.getModifiers())) { - if (!method.isAccessible()) { - method.setAccessible(true); - } - return new ValueOfBasedConverter(clazz, method); - } else { - // The valueOf method is present but it must be static. - return null; - } - } catch (NoSuchMethodException e) { - // The class does not have the right method, return null. - return null; - } - - } - - /** - * Converts the given input to an object by using the 'valueOf' method. Notice that the method may - * receive a {@literal null} value. - * - * @param input the input, can be {@literal null} - * @return the instance of T - * @throws IllegalArgumentException if the instance of T cannot be created from the input. - */ - @Override - public T fromString(String input) throws IllegalArgumentException { - try { - return clazz.cast(method.invoke(null, input)); - } catch (IllegalAccessException | InvocationTargetException e) { - if (e.getCause() != null) { - throw new IllegalArgumentException(e.getCause()); - } else { - throw new IllegalArgumentException(e); - } - } - } -} diff --git a/src/main/java/io/vertx/core/cli/impl/DefaultCLI.java b/src/main/java/io/vertx/core/cli/impl/DefaultCLI.java deleted file mode 100644 index a66749d5ead..00000000000 --- a/src/main/java/io/vertx/core/cli/impl/DefaultCLI.java +++ /dev/null @@ -1,254 +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.cli.impl; - -import io.vertx.core.cli.*; - -import java.util.*; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -/** - * Default implementation of {@link CLI}. - * - * @author Clement Escoffier - */ -public class DefaultCLI implements CLI { - - protected String name; - protected int priority; - protected String description; - protected String summary; - protected boolean hidden; - - protected List

- * --L - * --L=V - * --L V - * --l - * - * @param token the command line token to handle - */ - private void handleLongOption(String token) throws CLIException { - if (token.indexOf('=') == -1) { - handleLongOptionWithoutEqual(token); - } else { - handleLongOptionWithEqual(token); - } - } - - /** - * Handles the following tokens: - *

- * --L - * -L - * --l - * -l - * - * @param token the command line token to handle - */ - private void handleLongOptionWithoutEqual(String token) throws CLIException { - List

- * --L=V - * -L=V - * --l=V - * -l=V - * - * @param token the command line token to handle - */ - private void handleLongOptionWithEqual(String token) throws CLIException { - int pos = token.indexOf('='); - - String value = token.substring(pos + 1); - - String opt = token.substring(0, pos); - - List

- * -S - * -SV - * -S V - * -S=V - *

- * -L - * -LV - * -L V - * -L=V - * -l - * - * @param token the command line token to handle - */ - private void handleShortAndLongOption(String token) throws CLIException { - String t = stripLeadingHyphens(token); - int pos = t.indexOf('='); - - if (t.length() == 1) { - // -S - if (hasOptionWithShortName(t)) { - handleOption(getOption(t)); - } else { - handleArgument(token); - } - } else if (pos == -1) { - // no equal sign found (-xxx) - if (hasOptionWithShortName(t)) { - handleOption(getOption(t)); - } else if (!getMatchingOptions(t).isEmpty()) { - // -L or -l - handleLongOptionWithoutEqual(token); - } else { - // look for a long prefix (-Xmx512m) - String opt = getLongPrefix(t); - if (opt != null) { - if (commandLine.acceptMoreValues(getOption(opt))) { - handleOption(getOption(opt)); - commandLine.addRawValue(getOption(opt), t.substring(opt.length())); - current = null; - } else { - throw new InvalidValueException(getOption(opt), t.substring(opt.length())); - } - } else if (isAValidShortOption(t)) { - // -SV1 (-Dflag) - String strip = t.substring(0, 1); - Option option = getOption(strip); - handleOption(option); - commandLine.addRawValue(current, t.substring(1)); - current = null; - } else { - // -S1S2S3 or -S1S2V - handleConcatenatedOptions(token); - } - } - } else { - // equal sign found (-xxx=yyy) - String opt = t.substring(0, pos); - String value = t.substring(pos + 1); - if (opt.length() == 1) { - // -S=V - Option option = getOption(opt); - if (option != null) { - if (commandLine.acceptMoreValues(option)) { - handleOption(option); - commandLine.addRawValue(option, value); - current = null; - } else { - throw new InvalidValueException(option, value); - } - } else { - handleArgument(token); - } - } else if (isAValidShortOption(opt) && !hasOptionWithLongName(opt)) { - // -SV1=V2 (-Dkey=value) - handleOption(getOption(opt.substring(0, 1))); - commandLine.addRawValue(current, opt.substring(1) + "=" + value); - current = null; - } else { - // -L=V or -l=V - handleLongOptionWithEqual(token); - } - } - } - - /** - * Search for a prefix that is the long name of an option (-Xmx512m) - * - * @param token the token - * @return the found prefix. - */ - private String getLongPrefix(String token) { - String t = stripLeadingHyphens(token); - - int i; - String opt = null; - for (i = t.length() - 2; i > 1; i--) { - String prefix = t.substring(0, i); - if (hasOptionWithLongName(prefix)) { - opt = prefix; - break; - } - } - return opt; - } - - private boolean hasOptionWithLongName(String name) { - for (Option option : cli.getOptions()) { - if (name.equals(option.getLongName())) { - return true; - } - } - return false; - } - - private boolean hasOptionWithShortName(String name) { - for (Option option : cli.getOptions()) { - if (name.equals(option.getShortName())) { - return true; - } - } - return false; - } - - private void handleOption(Option option) throws CLIException { - // check the previous option before handling the next one - checkRequiredValues(); - updateRequiredOptions(option); - //IMPORTANT for flag we must set this attributes as it will determine the value out of it. - commandLine.setSeenInCommandLine(option); - if (commandLine.acceptMoreValues(option)) { - current = option; - } else { - current = null; - } - } - - /** - * Removes the option from the list of expected elements. - * - * @param option the option - */ - private void updateRequiredOptions(Option option) { - if (option.isRequired()) { - expectedOpts.remove(option); - } - } - - /** - * Retrieve the {@link Option} matching the long or short name specified. - * The leading hyphens in the name are ignored (up to 2). - * - * @param opt short or long name of the {@link Option} - * @return the option represented by opt - */ - public Option getOption(String opt) { - opt = stripLeadingHyphens(opt); - for (Option option : cli.getOptions()) { - if (opt.equals(option.getShortName()) || opt.equalsIgnoreCase(option.getLongName())) { - return option; - } - } - return null; - } - - private boolean isAValidShortOption(String token) { - String opt = token.substring(0, 1); - Option option = getOption(opt); - return option != null && commandLine.acceptMoreValues(option); - } - - /** - * Returns the options with a long name starting with the name specified. - * - * @param opt the partial name of the option - * @return the options matching the partial name specified, or an empty list if none matches - */ - public List

- * If the argument doesn't include spaces or quotes, return it as is. If it - * contains double quotes, use single quotes - else surround the argument by - * double quotes. - *

- * - * @param argument the argument to be quoted - * @return the quoted argument - * @throws IllegalArgumentException If argument contains both types of quotes - */ - public static String quoteArgument(final String argument) { - - String cleanedArgument = argument.trim(); - - // strip the quotes from both ends - while (cleanedArgument.startsWith(SINGLE_QUOTE) && cleanedArgument.endsWith(SINGLE_QUOTE) - || cleanedArgument.startsWith(DOUBLE_QUOTE) && cleanedArgument.endsWith(DOUBLE_QUOTE)) { - cleanedArgument = cleanedArgument.substring(1, cleanedArgument.length() - 1); - } - - final StringBuilder buf = new StringBuilder(); - if (cleanedArgument.contains(DOUBLE_QUOTE)) { - if (cleanedArgument.contains(SINGLE_QUOTE)) { - throw new IllegalArgumentException( - "Can't handle single and double quotes in same argument"); - } - if (Utils.isWindows()) { - return buf.append(DOUBLE_QUOTE).append(cleanedArgument.replace("\"", "\\\"")).append(DOUBLE_QUOTE).toString(); - } else { - return buf.append(SINGLE_QUOTE).append(cleanedArgument).append( - SINGLE_QUOTE).toString(); - } - } else if (cleanedArgument.contains(SINGLE_QUOTE) - || cleanedArgument.contains(" ")) { - return buf.append(DOUBLE_QUOTE).append(cleanedArgument).append( - DOUBLE_QUOTE).toString(); - } else { - return cleanedArgument; - } - } - - /** - * Adds an argument to the given list. It automatically adds quotes to the argument if necessary. - * - * @param args the list of arguments - * @param argument the argument to add - */ - public static void addArgument(List args, String argument) { - args.add(quoteArgument(argument)); - } - - /** - * @return {@code true} if the current operating system belongs to the "windows" family. - */ - public static boolean isWindows() { - return osName.contains("windows"); - } - - /** - * @return {@code true} if the current operating system belongs to the "linux" family. - */ - public static boolean isLinux() { - return osName.contains("nux"); - } - - /** - * Exits the JVM with the given exit code. - * - * @param code the code, {@code 0} for success. By convention a non zero value if return to denotes an - * error. - */ - public static void exit(int code) { - System.exit(code); - } - - /** - * Exits the JVM and indicate an issue during the Vert.x initialization. - */ - public static void exitBecauseOfVertxInitializationIssue() { - exit(VERTX_INITIALIZATION_EXIT_CODE); - } - - /** - * Exits the JVM and indicate an issue during the deployment of the main verticle. - */ - public static void exitBecauseOfVertxDeploymentIssue() { - exit(VERTX_DEPLOYMENT_EXIT_CODE); - } - - /** - * Exits the JVM and indicate an issue with a process creation or termination. - */ - public static void exitBecauseOfProcessIssue() { - exit(PROCESS_ERROR_EXIT_CODE); - } - - /** - * Exits the JVM and indicate an issue with the system configuration. - */ - public static void exitBecauseOfSystemConfigurationIssue() { - exit(SYSTEM_CONFIGURATION_EXIT_CODE); - } - - -} diff --git a/src/main/java/io/vertx/core/impl/launcher/commands/FileSelector.java b/src/main/java/io/vertx/core/impl/launcher/commands/FileSelector.java deleted file mode 100644 index 1adc7951439..00000000000 --- a/src/main/java/io/vertx/core/impl/launcher/commands/FileSelector.java +++ /dev/null @@ -1,365 +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.impl.launcher.commands; - - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.StringTokenizer; - -/** - * Utility methods to test path matching. This is used by the {@link Watcher} to determine whether or not a file - * triggers a redeployment. - * - * @author Clement Escoffier - */ -public final class FileSelector { - - /** - * When the pattern starts with a {@link File#separator}, {@code str} has to start with a {@link File#separator}. - * - * @return {@code true} when @{code str} starts with a {@link File#separator}, and {@code pattern} starts with a - * {@link File#separator}. - */ - private static boolean separatorPatternStartSlashMismatch(String pattern, String str, String separator) { - return str.startsWith(separator) != pattern.startsWith(separator); - } - - /** - * Tests whether or not a given path matches a given pattern. - * - * @param pattern The pattern to match against. Must not be - * {@code null}. - * @param str The path to match, as a String. Must not be - * {@code null}. - * @return {@code true} if the pattern matches against the string, - * or {@code false} otherwise. - */ - public static boolean matchPath(String pattern, String str) { - return matchPath(pattern, str, true); - } - - /** - * Tests whether or not a given path matches a given pattern. - * - * @param pattern The pattern to match against. Must not be - * {@code null}. - * @param str The path to match, as a String. Must not be - * {@code null}. - * @param isCaseSensitive Whether or not matching should be performed - * case sensitively. - * @return {@code true} if the pattern matches against the string, - * or {@code false} otherwise. - */ - public static boolean matchPath(String pattern, String str, boolean isCaseSensitive) { - return matchPath(pattern, str, File.separator, isCaseSensitive); - } - - protected static boolean matchPath(String pattern, String str, String separator, boolean isCaseSensitive) { - return matchPathPattern(pattern, str, separator, isCaseSensitive); - } - - private static boolean matchPathPattern(String pattern, String str, String separator, boolean isCaseSensitive) { - if (separatorPatternStartSlashMismatch(pattern, str, separator)) { - return false; - } - String[] patDirs = tokenizePathToString(pattern, separator); - String[] strDirs = tokenizePathToString(str, separator); - return matchPathPattern(patDirs, strDirs, isCaseSensitive); - - } - - private static boolean matchPathPattern(String[] patDirs, String[] strDirs, boolean isCaseSensitive) { - int patIdxStart = 0; - int patIdxEnd = patDirs.length - 1; - int strIdxStart = 0; - int strIdxEnd = strDirs.length - 1; - - // up to first '**' - while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { - String patDir = patDirs[patIdxStart]; - if (patDir.equals("**")) { - break; - } - if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) { - return false; - } - patIdxStart++; - strIdxStart++; - } - if (strIdxStart > strIdxEnd) { - // String is exhausted - for (int i = patIdxStart; i <= patIdxEnd; i++) { - if (!patDirs[i].equals("**")) { - return false; - } - } - return true; - } else { - if (patIdxStart > patIdxEnd) { - // String not exhausted, but pattern is. Failure. - return false; - } - } - - // up to last '**' - while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { - String patDir = patDirs[patIdxEnd]; - if (patDir.equals("**")) { - break; - } - if (!match(patDir, strDirs[strIdxEnd], isCaseSensitive)) { - return false; - } - patIdxEnd--; - strIdxEnd--; - } - if (strIdxStart > strIdxEnd) { - // String is exhausted - for (int i = patIdxStart; i <= patIdxEnd; i++) { - if (!patDirs[i].equals("**")) { - return false; - } - } - return true; - } - - while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { - int patIdxTmp = -1; - for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { - if (patDirs[i].equals("**")) { - patIdxTmp = i; - break; - } - } - if (patIdxTmp == patIdxStart + 1) { - // '**/**' situation, so skip one - patIdxStart++; - continue; - } - // Find the pattern between padIdxStart & padIdxTmp in str between - // strIdxStart & strIdxEnd - int patLength = (patIdxTmp - patIdxStart - 1); - int strLength = (strIdxEnd - strIdxStart + 1); - int foundIdx = -1; - strLoop: - for (int i = 0; i <= strLength - patLength; i++) { - for (int j = 0; j < patLength; j++) { - String subPat = patDirs[patIdxStart + j + 1]; - String subStr = strDirs[strIdxStart + i + j]; - if (!match(subPat, subStr, isCaseSensitive)) { - continue strLoop; - } - } - - foundIdx = strIdxStart + i; - break; - } - - if (foundIdx == -1) { - return false; - } - - patIdxStart = patIdxTmp; - strIdxStart = foundIdx + patLength; - } - - for (int i = patIdxStart; i <= patIdxEnd; i++) { - if (!patDirs[i].equals("**")) { - return false; - } - } - - return true; - } - - /** - * Tests whether or not a string matches against a pattern. - * The pattern may contain two special characters:
- * '*' means zero or more characters
- * '?' means one and only one character - * - * @param pattern The pattern to match against. - * Must not be{@code null}. - * @param str The string which must be matched against the pattern. - * Must not be{@code null}. - * @return {@code true} if the string matches against the pattern, - * or {@code false} otherwise. - */ - public static boolean match(String pattern, String str) { - return match(pattern, str, true); - } - - /** - * Tests whether or not a string matches against a pattern. - * The pattern may contain two special characters:
- * '*' means zero or more characters
- * '?' means one and only one character - * - * @param pattern The pattern to match against. - * Must not be{@code null}. - * @param str The string which must be matched against the pattern. - * Must not be{@code null}. - * @param isCaseSensitive Whether or not matching should be performed - * case sensitively. - * @return {@code true} if the string matches against the pattern, - * or {@code false} otherwise. - */ - public static boolean match(String pattern, String str, boolean isCaseSensitive) { - char[] patArr = pattern.toCharArray(); - char[] strArr = str.toCharArray(); - return match(patArr, strArr, isCaseSensitive); - } - - private static boolean match(char[] patArr, char[] strArr, boolean isCaseSensitive) { - int patIdxStart = 0; - int patIdxEnd = patArr.length - 1; - int strIdxStart = 0; - int strIdxEnd = strArr.length - 1; - char ch; - - boolean containsStar = false; - for (char aPatArr : patArr) { - if (aPatArr == '*') { - containsStar = true; - break; - } - } - - if (!containsStar) { - // No '*'s, so we make a shortcut - if (patIdxEnd != strIdxEnd) { - return false; // Pattern and string do not have the same size - } - for (int i = 0; i <= patIdxEnd; i++) { - ch = patArr[i]; - if (ch != '?' && !equals(ch, strArr[i], isCaseSensitive)) { - return false; // Character mismatch - } - } - return true; // String matches against pattern - } - - if (patIdxEnd == 0) { - return true; // Pattern contains only '*', which matches anything - } - - // Process characters before first star - while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) { - if (ch != '?' && !equals(ch, strArr[strIdxStart], isCaseSensitive)) { - return false; // Character mismatch - } - patIdxStart++; - strIdxStart++; - } - if (strIdxStart > strIdxEnd) { - return checkOnlyStartsLeft(patArr, patIdxStart, patIdxEnd); - } - - // Process characters after last star - while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) { - if (ch != '?' && !equals(ch, strArr[strIdxEnd], isCaseSensitive)) { - return false; // Character mismatch - } - patIdxEnd--; - strIdxEnd--; - } - if (strIdxStart > strIdxEnd) { - // All characters in the string are used. Check if only '*'s are - // left in the pattern. If so, we succeeded. Otherwise failure. - return checkOnlyStartsLeft(patArr, patIdxStart, patIdxEnd); - } - - // process pattern between stars. padIdxStart and patIdxEnd point - // always to a '*'. - while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { - int patIdxTmp = -1; - for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { - if (patArr[i] == '*') { - patIdxTmp = i; - break; - } - } - if (patIdxTmp == patIdxStart + 1) { - // Two stars next to each other, skip the first one. - patIdxStart++; - continue; - } - // Find the pattern between padIdxStart & padIdxTmp in str between - // strIdxStart & strIdxEnd - int patLength = (patIdxTmp - patIdxStart - 1); - int strLength = (strIdxEnd - strIdxStart + 1); - int foundIdx = -1; - strLoop: - for (int i = 0; i <= strLength - patLength; i++) { - for (int j = 0; j < patLength; j++) { - ch = patArr[patIdxStart + j + 1]; - if (ch != '?' && !equals(ch, strArr[strIdxStart + i + j], isCaseSensitive)) { - continue strLoop; - } - } - - foundIdx = strIdxStart + i; - break; - } - - if (foundIdx == -1) { - return false; - } - - patIdxStart = patIdxTmp; - strIdxStart = foundIdx + patLength; - } - - // All characters in the string are used. Check if only '*'s are left - // in the pattern. If so, we succeeded. Otherwise failure. - return checkOnlyStartsLeft(patArr, patIdxStart, patIdxEnd); - } - - private static boolean checkOnlyStartsLeft(char[] patArr, int patIdxStart, int patIdxEnd) { - // All characters in the string are used. Check if only '*'s are - // left in the pattern. If so, we succeeded. Otherwise failure. - for (int i = patIdxStart; i <= patIdxEnd; i++) { - if (patArr[i] != '*') { - return false; - } - } - return true; - } - - /** - * Tests whether two characters are equal. - */ - private static boolean equals(char c1, char c2, boolean isCaseSensitive) { - if (c1 == c2) { - return true; - } - if (!isCaseSensitive) { - // NOTE: Try both upper case and lower case as done by String.equalsIgnoreCase() - if (Character.toUpperCase(c1) == Character.toUpperCase(c2) - || Character.toLowerCase(c1) == Character.toLowerCase(c2)) { - return true; - } - } - return false; - } - - private static String[] tokenizePathToString(String path, String separator) { - List ret = new ArrayList<>(); - StringTokenizer st = new StringTokenizer(path, separator); - while (st.hasMoreTokens()) { - ret.add(st.nextToken()); - } - return ret.toArray(new String[0]); - } -} diff --git a/src/main/java/io/vertx/core/impl/launcher/commands/ListCommand.java b/src/main/java/io/vertx/core/impl/launcher/commands/ListCommand.java deleted file mode 100644 index c8d1b1748b5..00000000000 --- a/src/main/java/io/vertx/core/impl/launcher/commands/ListCommand.java +++ /dev/null @@ -1,131 +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.impl.launcher.commands; - - -import io.vertx.core.cli.annotations.Description; -import io.vertx.core.cli.annotations.Name; -import io.vertx.core.cli.annotations.Summary; -import io.vertx.core.spi.launcher.DefaultCommand; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A command listing launched vert.x instances. Instances are found using the `vertx.id` indicator in the - * process list. - * - * @author Clement Escoffier - */ -@Name("list") -@Summary("List vert.x applications") -@Description("List all vert.x applications launched with the `start` command") -public class ListCommand extends DefaultCommand { - - private final static Pattern PS = Pattern.compile("-Dvertx.id=(.*)\\s*"); - - private final static Pattern FAT_JAR_EXTRACTION = Pattern.compile("-jar (\\S*)"); - - private final static Pattern VERTICLE_EXTRACTION = Pattern.compile("run (\\S*)"); - - // Note about stack traces - the stack trace are printed on the stream passed to the command. - - /** - * Executes the {@code list} command. - */ - @Override - public void run() { - out.println("Listing vert.x applications..."); - List cmd = new ArrayList<>(); - if (!ExecUtils.isWindows()) { - try { - cmd.add("sh"); - cmd.add("-c"); - cmd.add("ps ax | grep \"vertx.id=\""); - - dumpFoundVertxApplications(cmd); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - e.printStackTrace(out); - } catch (Exception e) { - e.printStackTrace(out); - } - - } else { - try { - // Use wmic. - cmd.add("WMIC"); - cmd.add("PROCESS"); - cmd.add("WHERE"); - cmd.add("CommandLine like '%java.exe%'"); - cmd.add("GET"); - cmd.add("CommandLine"); - cmd.add("/VALUE"); - - dumpFoundVertxApplications(cmd); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - e.printStackTrace(out); - } catch (Exception e) { - e.printStackTrace(out); - } - } - - - } - - private void dumpFoundVertxApplications(List cmd) throws IOException, InterruptedException { - boolean none = true; - final Process process = new ProcessBuilder(cmd).start(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { - String line; - while ((line = reader.readLine()) != null) { - final Matcher matcher = PS.matcher(line); - if (matcher.find()) { - String id = matcher.group(1); - String details = extractApplicationDetails(line); - out.println(id + "\t" + details); - none = false; - } - } - process.waitFor(); - } - if (none) { - out.println("No vert.x application found."); - } - } - - /** - * Tries to extract the fat jar name of the verticle name. It's a best-effort approach looking at the name of the - * jar or to the verticle name from the command line. If not found, no details are returned (empty string). - * - * @return the details, empty if it cannot be extracted. - */ - protected static String extractApplicationDetails(String line) { - Matcher matcher = FAT_JAR_EXTRACTION.matcher(line); - if (matcher.find()) { - return matcher.group(1); - } else { - matcher = VERTICLE_EXTRACTION.matcher(line); - if (matcher.find()) { - return matcher.group(1); - } - } - // No details. - return ""; - } -} diff --git a/src/main/java/io/vertx/core/impl/launcher/commands/ListCommandFactory.java b/src/main/java/io/vertx/core/impl/launcher/commands/ListCommandFactory.java deleted file mode 100644 index a7f24042ab8..00000000000 --- a/src/main/java/io/vertx/core/impl/launcher/commands/ListCommandFactory.java +++ /dev/null @@ -1,28 +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.impl.launcher.commands; - -import io.vertx.core.spi.launcher.DefaultCommandFactory; - -/** - * Defines the `list` command. - * - * @author Clement Escoffier - */ -public class ListCommandFactory extends DefaultCommandFactory { - /** - * Creates a new {@link ListCommandFactory}. - */ - public ListCommandFactory() { - super(ListCommand.class, ListCommand::new); - } -} diff --git a/src/main/java/io/vertx/core/impl/launcher/commands/RunCommand.java b/src/main/java/io/vertx/core/impl/launcher/commands/RunCommand.java deleted file mode 100644 index 1c4c9a26896..00000000000 --- a/src/main/java/io/vertx/core/impl/launcher/commands/RunCommand.java +++ /dev/null @@ -1,454 +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.impl.launcher.commands; - -import io.vertx.core.*; -import io.vertx.core.cli.CLIException; -import io.vertx.core.cli.CommandLine; -import io.vertx.core.cli.annotations.*; -import io.vertx.core.impl.VertxInternal; -import io.vertx.core.impl.launcher.VertxLifecycleHooks; -import io.vertx.core.json.JsonObject; -import io.vertx.core.spi.launcher.ExecutionContext; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; - -/** - * The vert.x run command that lets you execute verticles. - * - * @author Clement Escoffier - */ -@Name("run") -@Summary("Runs a verticle called in its own instance of vert.x.") -public class RunCommand extends BareCommand implements Closeable { - - protected DeploymentOptions deploymentOptions; - - protected boolean cluster; - protected boolean ha; - - protected int instances; - protected String config; - protected boolean worker; - - protected String mainVerticle; - protected List redeploy; - - - protected String vertxApplicationBackgroundId; - protected String onRedeployCommand; - protected Watcher watcher; - private long redeployScanPeriod; - private long redeployGracePeriod; - private long redeployTerminationPeriod; - - /** - * Enables / disables the high-availability. - * - * @param ha whether or not to enable the HA. - */ - @Option(longName = "ha", acceptValue = false, flag = true) - @Description("If specified the verticle will be deployed as a high availability (HA) deployment. This means it can " + - "fail over to any other nodes in the cluster started with the same HA group.") - public void setHighAvailability(boolean ha) { - this.ha = ha; - } - - /** - * Enables / disables the clustering. - * - * @param cluster whether or not to start vert.x in clustered mode. - */ - @Option(longName = "cluster", acceptValue = false, flag = true) - @Description("If specified then the vert.x instance will form a cluster with any other vert.x instances on the " + - "network.") - public void setCluster(boolean cluster) { - this.cluster = cluster; - } - - /** - * Whether or not the verticle is deployed as a worker verticle. - * - * @param worker {@code true} to deploy the verticle as worker, {@code false} otherwise - */ - @Option(longName = "worker", acceptValue = false) - @Description("If specified then the verticle is a worker verticle.") - public void setWorker(boolean worker) { - this.worker = worker; - } - - /** - * Sets the number of instance of the verticle to create. - * - * @param instances the number of instances - */ - @Option(longName = "instances", argName = "instances") - @DefaultValue("1") - @Description("Specifies how many instances of the verticle will be deployed. Defaults to 1.") - public void setInstances(int instances) { - this.instances = instances; - } - - /** - * The main verticle configuration, it can be a json file or a json string. - * - * @param configuration the configuration - */ - @Option(longName = "conf", argName = "config") - @Description("Specifies configuration that should be provided to the verticle. should reference either a " + - "text file containing a valid JSON object which represents the configuration OR be a JSON string.") - public void setConfig(String configuration) { - if (configuration != null) { - // For inlined configuration remove first and end single and double quotes if any - this.config = configuration.trim() - .replaceAll("^\"|\"$", "") - .replaceAll("^'|'$", ""); - } else { - this.config = null; - } - } - - /** - * Sets the main verticle that is deployed. - * - * @param verticle the verticle - */ - @Argument(index = 0, argName = "main-verticle", required = true) - @Description("The main verticle to deploy, it can be a fully qualified class name or a file.") - public void setMainVerticle(String verticle) { - this.mainVerticle = verticle; - } - - @Option(longName = "redeploy", argName = "includes") - @Description("Enable automatic redeployment of the application. This option takes a set on includes as parameter " + - "indicating which files need to be watched. Patterns are separated by a comma.") - @ParsedAsList - public void setRedeploy(List redeploy) { - this.redeploy = redeploy; - } - - /** - * Sets the user command executed during redeployment. - * - * @param command the on redeploy command - * @deprecated Use 'on-redeploy' instead. It will be removed in vert.x 3.3 - */ - @Option(longName = "onRedeploy", argName = "cmd") - @Description("Optional shell command executed when a redeployment is triggered (deprecated - will be removed in 3" + - ".3, use 'on-redeploy' instead") - @Hidden - @Deprecated - public void setOnRedeployCommandOld(String command) { - out.println("[WARNING] the 'onRedeploy' option is deprecated, and will be removed in vert.x 3.3. Use " + - "'on-redeploy' instead."); - setOnRedeployCommand(command); - } - - @Option(longName = "on-redeploy", argName = "cmd") - @Description("Optional shell command executed when a redeployment is triggered") - public void setOnRedeployCommand(String command) { - this.onRedeployCommand = command; - } - - @Option(longName = "redeploy-scan-period", argName = "period") - @Description("When redeploy is enabled, this option configures the file system scanning period to detect file " + - "changes. The time is given in milliseconds. 250 ms by default.") - @DefaultValue("250") - public void setRedeployScanPeriod(long period) { - this.redeployScanPeriod = period; - } - - @Option(longName = "redeploy-grace-period", argName = "period") - @Description("When redeploy is enabled, this option configures the grace period between 2 redeployments. The time " + - "is given in milliseconds. 1000 ms by default.") - @DefaultValue("1000") - public void setRedeployGracePeriod(long period) { - this.redeployGracePeriod = period; - } - - @Option(longName = "redeploy-termination-period", argName = "period") - @Description("When redeploy is enabled, this option configures the time waited to be sure that the previous " + - "version of the application has been stopped. It is useful on Windows, where the 'terminate' command may take time to be " + - "executed.The time is given in milliseconds. 0 ms by default.") - @DefaultValue("0") - public void setRedeployStopWaitingTime(long period) { - this.redeployTerminationPeriod = period; - } - - /** - * Validates the command line parameters. - * - * @param context - the execution context - * @throws CLIException - validation failed - */ - @Override - public void setUp(ExecutionContext context) throws CLIException { - super.setUp(context); - - CommandLine commandLine = executionContext.commandLine(); - if (!isClustered() && ( - commandLine.isOptionAssigned(executionContext.cli().getOption("cluster-host")) - || commandLine.isOptionAssigned(executionContext.cli().getOption("cluster-port")) - || commandLine.isOptionAssigned(executionContext.cli().getOption("cluster-public-host")) - || commandLine.isOptionAssigned(executionContext.cli().getOption("cluster-public-port")) - )) { - throw new CLIException("The -cluster-xxx options require -cluster to be enabled"); - } - - // If quorum and / or ha-group, ha need to have been explicitly set - io.vertx.core.cli.Option haGroupOption = executionContext.cli().getOption("hagroup"); - io.vertx.core.cli.Option quorumOption = executionContext.cli().getOption("quorum"); - if (!ha && - (commandLine.isOptionAssigned(haGroupOption) || commandLine.isOptionAssigned(quorumOption))) { - throw new CLIException("The option -hagroup and -quorum requires -ha to be enabled"); - } - } - - /** - * @return whether the {@code cluster} option or the {@code ha} option are enabled. Also {@code true} when a custom - * launcher modifies the Vert.x options to set `clustered` to {@code true} - */ - @Override - public boolean isClustered() { - return cluster || ha; - } - - @Override - public boolean getHA() { - return ha; - } - - /** - * Starts vert.x and deploy the verticle. - */ - @Override - public void run() { - if (redeploy == null || redeploy.isEmpty()) { - JsonObject conf = getConfiguration(); - if (conf == null) { - conf = new JsonObject(); - } - afterConfigParsed(conf); - - super.run(this::afterStoppingVertx); - if (vertx == null) { - // Already logged. - ExecUtils.exitBecauseOfVertxInitializationIssue(); - } - - if (vertx instanceof VertxInternal) { - ((VertxInternal) vertx).addCloseHook(this); - } - - deploymentOptions = new DeploymentOptions(); - configureFromSystemProperties(deploymentOptions, DEPLOYMENT_OPTIONS_PROP_PREFIX); - deploymentOptions.setConfig(conf).setWorker(worker).setHa(ha).setInstances(instances); - beforeDeployingVerticle(deploymentOptions); - deploy(); - } else { - // redeploy is set, start the redeployment infrastructure (watcher). - initializeRedeployment(); - } - } - - /** - * Initializes the redeployment cycle. In "redeploy mode", the application is launched as background, and is - * restarted after every change. A {@link Watcher} instance is responsible for monitoring files and triggering the - * redeployment. - */ - protected synchronized void initializeRedeployment() { - if (watcher != null) { - throw new IllegalStateException("Redeployment already started ? The watcher already exists"); - } - // Compute the application id. We append "-redeploy" to ease the identification in the process list. - vertxApplicationBackgroundId = UUID.randomUUID().toString() + "-redeploy"; - watcher = new Watcher(getCwd(), redeploy, - this::startAsBackgroundApplication, // On deploy - this::stopBackgroundApplication, // On undeploy - onRedeployCommand, // In between command - redeployGracePeriod, // The redeploy grace period - redeployScanPeriod); // The redeploy scan period - - // Close the watcher when the JVM is terminating. - // Notice that the vert.x finalizer is not registered when we run in redeploy mode. - Runtime.getRuntime().addShutdownHook(new Thread() { - public void run() { - shutdownRedeployment(); - } - }); - // Start the watching process, it triggers the initial deployment. - watcher.watch(); - } - - /** - * Stop the redeployment if started. - */ - protected synchronized void shutdownRedeployment() { - if (watcher != null) { - watcher.close(); - watcher = null; - } - } - - /** - * On-Undeploy action invoked while redeploying. It just stops the application launched in background. - * - * @param onCompletion an optional on-completion handler. If set it must be invoked at the end of this method. - */ - protected synchronized void stopBackgroundApplication(Handler onCompletion) { - executionContext.execute("stop", vertxApplicationBackgroundId, "--redeploy"); - if (redeployTerminationPeriod > 0) { - try { - Thread.sleep(redeployTerminationPeriod); - } catch (InterruptedException e) { - // Ignore the exception. - Thread.currentThread().interrupt(); - } - } - - if (onCompletion != null) { - onCompletion.handle(null); - } - } - - /** - * On-Deploy action invoked while redeploying. It just starts the application in background, copying all input - * parameters. In addition, the vertx application id is set. - * - * @param onCompletion an optional on-completion handler. If set it must be invoked at the end of this method. - */ - protected void startAsBackgroundApplication(Handler onCompletion) { - // We need to copy all options and arguments. - List args = new ArrayList<>(); - // Prepend the command. - args.add("run"); - args.add("--vertx-id=" + vertxApplicationBackgroundId); - args.addAll(executionContext.commandLine().allArguments()); - // No need to add the main-verticle as it's part of the allArguments list. - if (cluster) { - args.add("--cluster"); - } - if (clusterHost != null) { - args.add("--cluster-host=" + clusterHost); - } - if (clusterPort != 0) { - args.add("--cluster-port=" + clusterPort); - } - if (clusterPublicHost != null) { - args.add("--cluster-public-host=" + clusterPublicHost); - } - if (clusterPublicPort != -1) { - args.add("--cluster-public-port=" + clusterPublicPort); - } - if (ha) { - args.add("--ha"); - } - if (haGroup != null && !haGroup.equals("__DEFAULT__")) { - args.add("--hagroup=" + haGroup); - } - if (quorum != -1) { - args.add("--quorum=" + quorum); - } - if (classpath != null && !classpath.isEmpty()) { - args.add("--classpath=" + classpath.stream().collect(Collectors.joining(File.pathSeparator))); - } - if (vertxOptions != null) { - // Pass the configuration in 2 steps to quote correctly the options if it's an inlined json string - args.add("--options"); - args.add(vertxOptions); - } - if (config != null) { - // Pass the configuration in 2 steps to quote correctly the configuration if it's an inlined json string - args.add("--conf"); - args.add(config); - } - if (instances != 1) { - args.add("--instances=" + instances); - } - if (worker) { - args.add("--worker"); - } - if (systemProperties != null) { - args.addAll(systemProperties.stream().map(s -> "-D" + s).collect(Collectors.toList())); - } - - // Enable stream redirection - args.add("--redirect-output"); - - executionContext.execute("start", args.toArray(new String[0])); - if (onCompletion != null) { - onCompletion.handle(null); - } - } - - protected void deploy() { - deploy(mainVerticle, vertx, deploymentOptions, res -> { - if (res.failed()) { - handleDeployFailed(res.cause()); - } - }); - } - - private void handleDeployFailed(Throwable cause) { - if (executionContext.main() instanceof VertxLifecycleHooks) { - ((VertxLifecycleHooks) executionContext.main()).handleDeployFailed(vertx, mainVerticle, deploymentOptions, cause); - } else { - ExecUtils.exitBecauseOfVertxDeploymentIssue(); - } - } - - protected JsonObject getConfiguration() { - return getJsonFromFileOrString(config, "conf"); - } - - protected void beforeDeployingVerticle(DeploymentOptions deploymentOptions) { - final Object main = executionContext.main(); - if (main instanceof VertxLifecycleHooks) { - ((VertxLifecycleHooks) main).beforeDeployingVerticle(deploymentOptions); - } - } - - protected void afterConfigParsed(JsonObject config) { - final Object main = executionContext.main(); - if (main instanceof VertxLifecycleHooks) { - ((VertxLifecycleHooks) main).afterConfigParsed(config); - } - } - - protected void beforeStoppingVertx(Vertx vertx) { - final Object main = executionContext.main(); - if (main instanceof VertxLifecycleHooks) { - ((VertxLifecycleHooks) main).beforeStoppingVertx(vertx); - } - } - - protected void afterStoppingVertx() { - final Object main = executionContext.main(); - if (main instanceof VertxLifecycleHooks) { - ((VertxLifecycleHooks) main).afterStoppingVertx(); - } - } - - @Override - public void close(Promise completion) { - try { - beforeStoppingVertx(vertx); - completion.complete(); - } catch (Exception e) { - completion.fail(e); - } - } -} diff --git a/src/main/java/io/vertx/core/impl/launcher/commands/RunCommandFactory.java b/src/main/java/io/vertx/core/impl/launcher/commands/RunCommandFactory.java deleted file mode 100644 index 599e21e19ee..00000000000 --- a/src/main/java/io/vertx/core/impl/launcher/commands/RunCommandFactory.java +++ /dev/null @@ -1,29 +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.impl.launcher.commands; - -import io.vertx.core.spi.launcher.DefaultCommandFactory; - -/** - * Factory to create the {@code run} command. - * - * @author Clement Escoffier - */ -public class RunCommandFactory extends DefaultCommandFactory { - - /** - * Creates a new instance of {@link RunCommandFactory}. - */ - public RunCommandFactory() { - super(RunCommand.class, RunCommand::new); - } -} diff --git a/src/main/java/io/vertx/core/impl/launcher/commands/StartCommand.java b/src/main/java/io/vertx/core/impl/launcher/commands/StartCommand.java deleted file mode 100644 index 0b0e0b070b3..00000000000 --- a/src/main/java/io/vertx/core/impl/launcher/commands/StartCommand.java +++ /dev/null @@ -1,197 +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.impl.launcher.commands; - - -import io.vertx.core.cli.annotations.*; -import io.vertx.core.impl.launcher.CommandLineUtils; -import io.vertx.core.spi.launcher.DefaultCommand; - -import java.io.File; -import java.util.*; -import java.util.stream.Collectors; - -/** - * A command starting a vert.x application in the background. - * - * @author Clement Escoffier - */ -@Name("start") -@Summary("Start a vert.x application in background") -@Description("Start a vert.x application as a background service. The application is identified with an id that can be set using the `vertx-id` option. If not set a random UUID is generated. The application can be stopped with the `stop` command.") -public class StartCommand extends DefaultCommand { - - private String id; - private String launcher; - - private boolean redirect; - private String jvmOptions; - - /** - * Sets the "application id" that would be to stop the application and be lsited in the {@code list} command. - * - * @param id the id - */ - @Option(longName = "vertx-id", shortName = "id", required = false, acceptValue = true) - @Description("The id of the application, a random UUID by default") - public void setApplicationId(String id) { - this.id = id; - } - - /** - * Sets the Java Virtual Machine options to pass to the spawned process. If not set, the JAVA_OPTS environment - * variable is used. - * - * @param options the jvm options - */ - @Option(longName = "java-opts", required = false, acceptValue = true) - @Description("Java Virtual Machine options to pass to the spawned process such as \"-Xmx1G -Xms256m " + - "-XX:MaxPermSize=256m\". If not set the `JAVA_OPTS` environment variable is used.") - public void setJavaOptions(String options) { - this.jvmOptions = options; - } - - /** - * A hidden option to set the launcher class. - * - * @param clazz the class - */ - @Option(longName = "launcher-class") - @Hidden - public void setLauncherClass(String clazz) { - this.launcher = clazz; - } - - /** - * Whether or not the created process error streams and output streams needs to be redirected to the launcher process. - * - * @param redirect {@code true} to enable redirection, {@code false} otherwise - */ - @Option(longName = "redirect-output", flag = true) - @Hidden - public void setRedirect(boolean redirect) { - this.redirect = redirect; - } - - /** - * Starts the application in background. - */ - @Override - public void run() { - out.println("Starting vert.x application..."); - List cmd = new ArrayList<>(); - ProcessBuilder builder = new ProcessBuilder(); - addJavaCommand(cmd); - - // Must be called only once ! - List cliArguments = getArguments(); - - // Add the classpath to env. - builder.environment().put("CLASSPATH", System.getProperty("java.class.path")); - - if (launcher != null) { - ExecUtils.addArgument(cmd, launcher); - // Do we have a valid command ? - Optional maybeCommand = cliArguments.stream() - .filter(arg -> executionContext.launcher().getCommandNames().contains(arg)) - .findFirst(); - if (! maybeCommand.isPresent()) { - // No command, add `run` - ExecUtils.addArgument(cmd, "run"); - } - } else if (isLaunchedAsFatJar()) { - ExecUtils.addArgument(cmd, "-jar"); - ExecUtils.addArgument(cmd, CommandLineUtils.getJar()); - } else { - // probably a `vertx` command line usage, or in IDE. - ExecUtils.addArgument(cmd, CommandLineUtils.getFirstSegmentOfCommand()); - ExecUtils.addArgument(cmd, "run"); - } - - cliArguments.forEach(arg -> ExecUtils.addArgument(cmd, arg)); - - try { - builder.command(cmd); - if (redirect) { - builder.redirectError(ProcessBuilder.Redirect.INHERIT); - builder.redirectOutput(ProcessBuilder.Redirect.INHERIT); - } - builder.start(); - out.println(id); - } catch (Exception e) { - out.println("Cannot create vert.x application process"); - e.printStackTrace(out); - ExecUtils.exitBecauseOfProcessIssue(); - } - - } - - private void addJavaCommand(List cmd) { - if (ExecUtils.isWindows()) { - ExecUtils.addArgument(cmd, "cmd.exe"); - ExecUtils.addArgument(cmd, "/C"); - ExecUtils.addArgument(cmd, "start"); - ExecUtils.addArgument(cmd, "vertx-id - " + id); - ExecUtils.addArgument(cmd, "/B"); - } - ExecUtils.addArgument(cmd, getJava().getAbsolutePath()); - - // Compute JVM Options - if (jvmOptions == null) { - String opts = System.getenv("JAVA_OPTS"); - if (opts != null) { - Arrays.stream(opts.split(" ")).forEach(s -> ExecUtils.addArgument(cmd, s)); - } - } else { - Arrays.stream(jvmOptions.split(" ")).forEach(s -> ExecUtils.addArgument(cmd, s)); - } - } - - private File getJava() { - File java; - File home = new File(System.getProperty("java.home")); - if (ExecUtils.isWindows()) { - java = new File(home, "bin/java.exe"); - } else { - java = new File(home, "bin/java"); - } - - if (!java.isFile()) { - out.println("Cannot find java executable - " + java.getAbsolutePath() + " does not exist"); - ExecUtils.exitBecauseOfSystemConfigurationIssue(); - } - return java; - } - - private boolean isLaunchedAsFatJar() { - return CommandLineUtils.getJar() != null; - } - - private List getArguments() { - List args = executionContext.commandLine().allArguments(); - // Add system properties passed as parameter - if (systemProperties != null) { - systemProperties.stream().map(entry -> "-D" + entry).forEach(args::add); - } - - // Add id - it's important as it's the application mark. - args.add("-Dvertx.id=" + getId()); - return args; - } - - private String getId() { - if (id == null) { - id = UUID.randomUUID().toString(); - } - return id; - } -} diff --git a/src/main/java/io/vertx/core/impl/launcher/commands/StartCommandFactory.java b/src/main/java/io/vertx/core/impl/launcher/commands/StartCommandFactory.java deleted file mode 100644 index 16443e018ce..00000000000 --- a/src/main/java/io/vertx/core/impl/launcher/commands/StartCommandFactory.java +++ /dev/null @@ -1,29 +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.impl.launcher.commands; - -import io.vertx.core.spi.launcher.DefaultCommandFactory; - -/** - * Defines the `start` command. - * - * @author Clement Escoffier - */ -public class StartCommandFactory extends DefaultCommandFactory { - - /** - * Creates a new instance of {@link StartCommandFactory}. - */ - public StartCommandFactory() { - super(StartCommand.class, StartCommand::new); - } -} diff --git a/src/main/java/io/vertx/core/impl/launcher/commands/StopCommand.java b/src/main/java/io/vertx/core/impl/launcher/commands/StopCommand.java deleted file mode 100644 index a263e0cc7b9..00000000000 --- a/src/main/java/io/vertx/core/impl/launcher/commands/StopCommand.java +++ /dev/null @@ -1,158 +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.impl.launcher.commands; - -import io.vertx.core.cli.annotations.*; -import io.vertx.core.spi.launcher.DefaultCommand; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A command stopping a vert.x application launched using the `start` command. The application is - * identified by its id. - * - * @author Clement Escoffier - */ -@Name("stop") -@Summary("Stop a vert.x application") -@Description("This command stops a vert.x application started with the `start` command. The command requires the " + - "application id as argument. Use the `list` command to get the list of applications") -public class StopCommand extends DefaultCommand { - - private String id; - - /** - * Whether or not we are in redeploy mode. In redeploy mode, do not exit the VM. - */ - private boolean redeploy; - - - private static final Pattern PS = Pattern.compile("([0-9]+)\\s.*-Dvertx.id=.*"); - - /** - * As the {@code stop} command takes only a single argument, it's the application id. - * - * @param id the id. - */ - @Argument(index = 0, argName = "vertx.id", required = false) - @Description("The vert.x application id") - public void setApplicationId(String id) { - this.id = id; - } - - @Option(longName = "redeploy", flag = true) - @Hidden - public void setRedeploy(boolean redeploy) { - this.redeploy = redeploy; - } - - /** - * Stops a running vert.x application launched with the `start` command. - */ - @Override - public void run() { - if (id == null) { - out.println("Application id not specified..."); - executionContext.execute("list"); - return; - } - - out.println("Stopping vert.x application '" + id + "'"); - if (ExecUtils.isWindows()) { - terminateWindowsApplication(); - } else { - terminateLinuxApplication(); - } - } - - private void terminateLinuxApplication() { - String pid = pid(); - if (pid == null) { - out.println("Cannot find process for application using the id '" + id + "'."); - if (!redeploy) { - ExecUtils.exitBecauseOfProcessIssue(); - } - return; - } - - List cmd = new ArrayList<>(); - cmd.add("kill"); - cmd.add(pid); - try { - int result = new ProcessBuilder(cmd).start().waitFor(); - out.println("Application '" + id + "' terminated with status " + result); - if (!redeploy) { - // We leave the application using the same exit code. - ExecUtils.exit(result); - } - } catch (Exception e) { - out.println("Failed to stop application '" + id + "'"); - e.printStackTrace(out); - if (!redeploy) { - ExecUtils.exitBecauseOfProcessIssue(); - } - } - } - - private void terminateWindowsApplication() { - String filter = "Name LIKE 'java%' AND CommandLine LIKE '%-Dvertx.id=" + id + "%'"; - String command = - "\"Get-CimInstance -ClassName Win32_Process -Filter \\\"" + filter + "\\\"" + - " | " + - "Invoke-CimMethod -MethodName Terminate\""; - List cmd = Arrays.asList("powershell", "-Command", command); - - try { - final Process process = new ProcessBuilder(cmd).start(); - int result = process.waitFor(); - out.println("Application '" + id + "' terminated with status " + result); - if (!redeploy) { - // We leave the application using the same exit code. - ExecUtils.exit(result); - } - } catch (Exception e) { - out.println("Failed to stop application '" + id + "'"); - e.printStackTrace(out); - if (!redeploy) { - ExecUtils.exitBecauseOfProcessIssue(); - } - } - } - - private String pid() { - try { - final Process process = new ProcessBuilder(Arrays.asList("sh", "-c", "ps ax | grep \"" + id + "\"")).start(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { - String line; - while ((line = reader.readLine()) != null) { - final Matcher matcher = PS.matcher(line); - if (matcher.find()) { - return matcher.group(1); - } - } - process.waitFor(); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - e.printStackTrace(out); - } catch (Exception e) { - e.printStackTrace(out); - } - return null; - } -} diff --git a/src/main/java/io/vertx/core/impl/launcher/commands/StopCommandFactory.java b/src/main/java/io/vertx/core/impl/launcher/commands/StopCommandFactory.java deleted file mode 100644 index 05faf740e57..00000000000 --- a/src/main/java/io/vertx/core/impl/launcher/commands/StopCommandFactory.java +++ /dev/null @@ -1,29 +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.impl.launcher.commands; - -import io.vertx.core.spi.launcher.DefaultCommandFactory; - -/** - * Defines the `stop` command. - * - * @author Clement Escoffier - */ -public class StopCommandFactory extends DefaultCommandFactory { - - /** - * Creates a new instance of {@link StopCommandFactory}. - */ - public StopCommandFactory() { - super(StopCommand.class, StopCommand::new); - } -} diff --git a/src/main/java/io/vertx/core/impl/launcher/commands/VersionCommand.java b/src/main/java/io/vertx/core/impl/launcher/commands/VersionCommand.java deleted file mode 100644 index b5dfecd741f..00000000000 --- a/src/main/java/io/vertx/core/impl/launcher/commands/VersionCommand.java +++ /dev/null @@ -1,65 +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.impl.launcher.commands; - -import io.vertx.core.cli.CLIException; -import io.vertx.core.cli.annotations.Description; -import io.vertx.core.cli.annotations.Name; -import io.vertx.core.cli.annotations.Summary; -import io.vertx.core.impl.logging.Logger; -import io.vertx.core.impl.logging.LoggerFactory; -import io.vertx.core.spi.launcher.DefaultCommand; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Scanner; - -/** - * Comment to display the vert.x (core) version. - * - * @author Clement Escoffier - */ -@Name("version") -@Summary("Displays the version.") -@Description("Prints the vert.x core version used by the application.") -public class VersionCommand extends DefaultCommand { - - private static final Logger log = LoggerFactory.getLogger(VersionCommand.class); - - private static String version; - - @Override - public void run() throws CLIException { - log.info(getVersion()); - } - - /** - * Reads the version from the {@code vertx-version.txt} file. - * - * @return the version - */ - public static String getVersion() { - if (version != null) { - return version; - } - try (InputStream is = VersionCommand.class.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 version = scanner.hasNext() ? scanner.next().trim() : ""; - } - } catch (IOException e) { - throw new IllegalStateException(e.getMessage()); - } - } -} diff --git a/src/main/java/io/vertx/core/impl/launcher/commands/VersionCommandFactory.java b/src/main/java/io/vertx/core/impl/launcher/commands/VersionCommandFactory.java deleted file mode 100644 index 4136f796ddf..00000000000 --- a/src/main/java/io/vertx/core/impl/launcher/commands/VersionCommandFactory.java +++ /dev/null @@ -1,29 +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.impl.launcher.commands; - -import io.vertx.core.spi.launcher.DefaultCommandFactory; - -/** - * Factory to create the {@code version} command. - * - * @author Clement Escoffier - */ -public class VersionCommandFactory extends DefaultCommandFactory { - - /** - * Creates a new instance of {@link VersionCommandFactory}. - */ - public VersionCommandFactory() { - super(VersionCommand.class, VersionCommand::new); - } -} diff --git a/src/main/java/io/vertx/core/impl/launcher/commands/VertxIsolatedDeployer.java b/src/main/java/io/vertx/core/impl/launcher/commands/VertxIsolatedDeployer.java deleted file mode 100644 index 6d79812e834..00000000000 --- a/src/main/java/io/vertx/core/impl/launcher/commands/VertxIsolatedDeployer.java +++ /dev/null @@ -1,88 +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.impl.launcher.commands; - -import io.vertx.core.*; -import io.vertx.core.impl.logging.Logger; -import io.vertx.core.impl.logging.LoggerFactory; - -/** - * A class isolating the deployment of verticle. - * - * @author Clement Escoffier - */ -public class VertxIsolatedDeployer { - - private static final Logger log = LoggerFactory.getLogger(VertxIsolatedDeployer.class); - - private String deploymentId; - private Vertx vertx; - - /** - * Deploys the given verticle. - * - * @param verticle the verticle name - * @param vertx the vert.x instance - * @param options the deployment options - * @param completionHandler the completion handler - */ - public void deploy(String verticle, Vertx vertx, DeploymentOptions options, - Handler> completionHandler) { - this.vertx = vertx; - String message = (options.isWorker()) ? "deploying worker verticle" : "deploying verticle"; - vertx.deployVerticle(verticle, options).onComplete(createHandler(message, completionHandler)); - } - - /** - * Undeploys the previously deployed verticle. - * - * @param completionHandler the completion handler - */ - public void undeploy(Handler> completionHandler) { - vertx.undeploy(deploymentId).onComplete(res -> { - if (res.failed()) { - log.error("Failed in undeploying " + deploymentId, res.cause()); - } else { - log.info("Succeeded in undeploying " + deploymentId); - } - deploymentId = null; - completionHandler.handle(res); - }); - } - - - private Handler> createHandler(final String message, - final Handler> - completionHandler) { - return res -> { - if (res.failed()) { - Throwable cause = res.cause(); - if (cause instanceof VertxException) { - VertxException ve = (VertxException) cause; - if (ve.getCause() == null) { - log.error(ve.getMessage()); - } else { - log.error(ve.getMessage(), ve.getCause()); - } - } else { - log.error("Failed in " + message, cause); - } - } else { - deploymentId = res.result(); - log.info("Succeeded in " + message); - } - if (completionHandler != null) { - completionHandler.handle(res); - } - }; - } -} diff --git a/src/main/java/io/vertx/core/impl/launcher/commands/Watcher.java b/src/main/java/io/vertx/core/impl/launcher/commands/Watcher.java deleted file mode 100644 index e70a16aac3d..00000000000 --- a/src/main/java/io/vertx/core/impl/launcher/commands/Watcher.java +++ /dev/null @@ -1,360 +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.impl.launcher.commands; - -import io.vertx.core.Handler; -import io.vertx.core.impl.logging.Logger; -import io.vertx.core.impl.logging.LoggerFactory; - -import java.io.File; -import java.nio.file.WatchService; -import java.util.*; -import java.util.stream.Collectors; - -/** - * A file alteration monitor based on a home made file system scan and watching files matching a set of includes - * patterns. These patterns are Ant patterns (can use {@literal **, * or ?}). This class takes 2 {@link Handler} as - * parameter and orchestrate the redeployment method when a matching file is modified (created, updated or deleted). - * Users have the possibility to execute a shell command during the redeployment. On a file change, the {@code undeploy} - * {@link Handler} is called, followed by the execution of the user command. Then the {@code deploy} {@link Handler} - * is invoked. - *

- * The watcher watches all files from the current directory and sub-directories. - * - * @author Clement Escoffier - */ -public class Watcher implements Runnable { - - private final static Logger LOGGER = LoggerFactory.getLogger(Watcher.class); - - private final long gracePeriod; - private final Map> fileMap = new LinkedHashMap<>(); - private final Set filesToWatch = new HashSet<>(); - private final long scanPeriod; - private final List roots; - private final File cwd; - - /** - * This field is always access from the scan thread. No need to be volatile. - */ - private long lastChange = -1; - - private final List includes; - private final Handler> deploy; - private final Handler> undeploy; - private final String cmd; - - private volatile boolean closed; - - /** - * Creates a new {@link Watcher}. - * - * @param root the root directory - * @param includes the list of include patterns, should not be {@code null} or empty - * @param deploy the function called when deployment is required - * @param undeploy the function called when un-deployment is required - * @param onRedeployCommand an optional command executed after the un-deployment and before the deployment - * @param gracePeriod the amount of time in milliseconds to wait between two redeploy even - * if there are changes - * @param scanPeriod the time in millisecond between 2 file system scans - */ - public Watcher(File root, List includes, Handler> deploy, Handler> undeploy, - String onRedeployCommand, long gracePeriod, long scanPeriod) { - this.gracePeriod = gracePeriod; - this.includes = sanitizeIncludePatterns(includes); - this.roots = extractRoots(root, this.includes); - this.cwd = root; - LOGGER.info("Watched paths: " + this.roots); - this.deploy = deploy; - this.undeploy = undeploy; - this.cmd = onRedeployCommand; - this.scanPeriod = scanPeriod; - addFilesToWatchedList(roots); - } - - static List extractRoots(File root, List includes) { - return includes.stream().map(s -> { - if (s.startsWith("*")) { - return root.getAbsolutePath(); - } - if (s.contains("*")) { - s = s.substring(0, s.indexOf("*")); - } - File file = new File(s); - if (file.isAbsolute()) { - return file.getAbsolutePath(); - } else { - return new File(root, s).getAbsolutePath(); - } - }).collect(Collectors.toSet()).stream().map(File::new).collect(Collectors.toList()); - } - - private List sanitizeIncludePatterns(List includes) { - return includes.stream().map(p -> { - if (ExecUtils.isWindows()) { - return p.replace('/', File.separatorChar); - } - return p.replace('\\', File.separatorChar); - }).collect(Collectors.toList()); - } - - private void addFilesToWatchedList(List roots) { - roots.forEach(this::addFileToWatchedList); - } - - private void addFileToWatchedList(File file) { - filesToWatch.add(file); - Map map = new HashMap<>(); - if (file.isDirectory()) { - // We're watching a directory contents and its children for changes - File[] children = file.listFiles(); - if (children != null) { - for (File child : children) { - map.put(child, new FileInfo(child.lastModified(), child.length())); - if (child.isDirectory()) { - addFileToWatchedList(child); - } - } - } - } else { - // Not a directory - we're watching a specific file - e.g. a jar - map.put(file, new FileInfo(file.lastModified(), file.length())); - } - fileMap.put(file, map); - } - - /** - * Checks whether or not a change has occurred in one of the watched file that match one of the given include pattern - * . Are detected: new files, modified file and deleted files. File modification is detected using - * {@link File#lastModified()}, so the behavior depends on the file system precision. - * - * @return {@code true} if a change occurred requiring the redeployment. - */ - private boolean changesHaveOccurred() { - boolean changed = false; - for (File toWatch : new HashSet<>(filesToWatch)) { - - // The new files in the directory - Map newFiles = new LinkedHashMap<>(); - if (toWatch.isDirectory()) { - File[] files = toWatch.exists() ? toWatch.listFiles() : new File[]{}; - - if (files == null) { - // something really bad happened to the file system. - throw new IllegalStateException("Cannot scan the file system to detect file changes"); - } - - for (File file : files) { - newFiles.put(file, file); - } - } else { - newFiles.put(toWatch, toWatch); - } - - // Lookup the old list for that file/directory - Map currentFileMap = fileMap.get(toWatch); - for (Map.Entry currentEntry : new HashMap<>(currentFileMap).entrySet()) { - File currFile = currentEntry.getKey(); - FileInfo currInfo = currentEntry.getValue(); - File newFile = newFiles.get(currFile); - if (newFile == null) { - // File has been deleted - currentFileMap.remove(currFile); - if (currentFileMap.isEmpty()) { - fileMap.remove(toWatch); - filesToWatch.remove(toWatch); - } - LOGGER.trace("File: " + currFile + " has been deleted"); - if (match(currFile)) { - changed = true; - } - } else if (newFile.lastModified() != currInfo.lastModified || newFile.length() != currInfo.length) { - // File has been modified - currentFileMap.put(newFile, new FileInfo(newFile.lastModified(), newFile.length())); - LOGGER.trace("File: " + currFile + " has been modified"); - if (match(currFile)) { - changed = true; - } - } - } - - // Now process any added files - for (File newFile : newFiles.keySet()) { - if (!currentFileMap.containsKey(newFile)) { - // Add new file - currentFileMap.put(newFile, new FileInfo(newFile.lastModified(), newFile.length())); - if (newFile.isDirectory()) { - addFileToWatchedList(newFile); - } - LOGGER.trace("File was added: " + newFile); - if (match(newFile)) { - changed = true; - } - } - } - } - - long now = System.currentTimeMillis(); - if (changed) { - lastChange = now; - } - - if (lastChange != -1 && now - lastChange >= gracePeriod) { - lastChange = -1; - return true; - } - - return false; - } - - - /** - * Checks whether the given file matches one of the {@link #includes} patterns. - * - * @param file the file - * @return {@code true} if the file matches at least one pattern, {@code false} otherwise. - */ - protected boolean match(File file) { - // Compute relative path. - String rel = null; - String relFromCwd = null; - for (File root : roots) { - if (file.getAbsolutePath().startsWith(root.getAbsolutePath())) { - if (file.getAbsolutePath().equals(root.getAbsolutePath())) { - rel = file.getAbsolutePath(); - } else { - rel = file.getAbsolutePath().substring(root.getAbsolutePath().length() + 1); - } - } - } - if (rel == null) { - LOGGER.warn("A change in " + file.getAbsolutePath() + " has been detected, but the file does not belong to a " + - "watched roots: " + roots); - return false; - } - - if (file.getAbsolutePath().startsWith(cwd.getAbsolutePath())) { - relFromCwd = file.getAbsolutePath().substring(cwd.getAbsolutePath().length() + 1); - } - - for (String include : includes) { - // Windows files are not case sensitive - // 3 checks: two for the relative file (root and cwd), and one taking the absolute path, for pattern using - // absolute path - if ((relFromCwd != null && FileSelector.matchPath(include, relFromCwd, !ExecUtils.isWindows())) - || FileSelector.matchPath(include, file.getAbsolutePath(), !ExecUtils.isWindows())) { - return true; - } - } - return false; - } - - /** - * Starts watching. The watch processing is made in another thread started in this method. - * - * @return the current watcher. - */ - public Watcher watch() { - new Thread(this).start(); - LOGGER.info("Starting the vert.x application in redeploy mode"); - deploy.handle(null); - - return this; - } - - /** - * Stops watching. This method stops the underlying {@link WatchService}. - */ - public void close() { - LOGGER.info("Stopping redeployment"); - // closing the redeployment thread. If waiting, it will shutdown at the next iteration. - closed = true; - // Un-deploy application on close. - undeploy.handle(null); - } - - /** - * The watching thread runnable method. - */ - @Override - public void run() { - try { - while (!closed) { - if (changesHaveOccurred()) { - trigger(); - } - // Wait for the next scan. - Thread.sleep(scanPeriod); - } - } catch (Throwable e) { - LOGGER.error("An error have been encountered while watching resources - leaving the redeploy mode", e); - close(); - } - } - - /** - * Redeployment process. - */ - private void trigger() { - long begin = System.currentTimeMillis(); - LOGGER.info("Redeploying!"); - // 1) - undeploy.handle(v1 -> { - // 2) - executeUserCommand(v2 -> { - // 3) - deploy.handle(v3 -> { - long end = System.currentTimeMillis(); - LOGGER.info("Redeployment done in " + (end - begin) + " ms."); - }); - }); - }); - } - - private void executeUserCommand(Handler onCompletion) { - if (cmd != null) { - try { - List command = new ArrayList<>(); - if (ExecUtils.isWindows()) { - ExecUtils.addArgument(command, "cmd"); - ExecUtils.addArgument(command, "/c"); - } else { - ExecUtils.addArgument(command, "sh"); - ExecUtils.addArgument(command, "-c"); - } - // Do not add quote to the given command: - command.add(cmd); - - final Process process = new ProcessBuilder(command) - .redirectError(ProcessBuilder.Redirect.INHERIT) - .redirectOutput(ProcessBuilder.Redirect.INHERIT) - .start(); - - int status = process.waitFor(); - LOGGER.info("User command terminated with status " + status); - } catch (Throwable e) { - LOGGER.error("Error while executing the on-redeploy command : '" + cmd + "'", e); - } - } - onCompletion.handle(null); - } - - private static final class FileInfo { - long lastModified; - long length; - - private FileInfo(long lastModified, long length) { - this.lastModified = lastModified; - this.length = length; - } - } -} diff --git a/src/main/java/io/vertx/core/spi/VertxMetricsFactory.java b/src/main/java/io/vertx/core/spi/VertxMetricsFactory.java index d1d989e0076..2b99058851c 100644 --- a/src/main/java/io/vertx/core/spi/VertxMetricsFactory.java +++ b/src/main/java/io/vertx/core/spi/VertxMetricsFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2019 Contributors to the Eclipse Foundation + * Copyright (c) 2011-2023 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 @@ -13,14 +13,10 @@ import io.vertx.core.VertxOptions; import io.vertx.core.impl.VertxBuilder; -import io.vertx.core.impl.launcher.commands.BareCommand; import io.vertx.core.json.JsonObject; import io.vertx.core.metrics.MetricsOptions; -import io.vertx.core.metrics.impl.DummyVertxMetrics; import io.vertx.core.spi.metrics.VertxMetrics; -import static io.vertx.core.impl.launcher.commands.BareCommand.METRICS_OPTIONS_PROP_PREFIX; - /** * A factory for the plugable metrics SPI. * @@ -44,7 +40,6 @@ default void init(VertxBuilder builder) { metricsOptions = newOptions(metricsOptions); } } - BareCommand.configureFromSystemProperties(metricsOptions, METRICS_OPTIONS_PROP_PREFIX);; builder.options().setMetricsOptions(metricsOptions); if (options.getMetricsOptions().isEnabled()) { builder.metrics(metrics(options)); @@ -65,7 +60,6 @@ default void init(VertxBuilder builder) { /** * Create an empty metrics options. * Providers can override this method to provide a custom metrics options subclass that exposes custom configuration. - * It is used by the {@link io.vertx.core.Launcher} class when creating new options when building a CLI Vert.x. * * @implSpec The default implementation returns {@link MetricsOptions#MetricsOptions()} * @return new metrics options @@ -90,7 +84,6 @@ default MetricsOptions newOptions(MetricsOptions options) { /** * Create metrics options from the provided {@code jsonObject}. *

Providers can override this method to provide a custom metrics options subclass that exposes custom configuration. - *

It is used by the {@link io.vertx.core.Launcher} class when creating new options when building a CLI Vert.x. * * @implSpec The default implementation calls {@link MetricsOptions#MetricsOptions(JsonObject)} )} with {@code jsonObject} * @param jsonObject json provided by the user diff --git a/src/main/java/io/vertx/core/spi/launcher/Command.java b/src/main/java/io/vertx/core/spi/launcher/Command.java deleted file mode 100644 index f2cdbc10407..00000000000 --- a/src/main/java/io/vertx/core/spi/launcher/Command.java +++ /dev/null @@ -1,63 +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.spi.launcher; - -import io.vertx.core.cli.CLIException; -import io.vertx.core.cli.annotations.Argument; -import io.vertx.core.cli.annotations.Description; -import io.vertx.core.cli.annotations.Option; -import io.vertx.core.cli.annotations.Summary; - -/** - * A plug-in to the Vert.x command or {@link io.vertx.core.Launcher} class. Each command instance is created - * by a {@link CommandFactory}. - *

- * {@link Command} implementation can retrieve argument and option using the {@link Argument} and {@link - * Option} annotations. Documentation / help is provided using the {@link Summary} (single sentence) and - * {@link Description} annotations. - *

- * Commands follow a strict lifecycle. The {@link #setUp(ExecutionContext)} method is called with an - * execution context. It lets you validate the inputs and prepare the environment is needed. The - * {@link #run()} method is called immediately after {@link #setUp(ExecutionContext)}, and executes the - * command. Finally, once the command has completed, the {@link #tearDown()} method is called. In this method - * you have the opportunity to cleanup. - *

- * - * @author Clement Escoffier - */ -public interface Command { - - /** - * Set up the command execution environment. - * The command line model has been retrieved and is frozen. Values has been set / injected. You can use - * this callback to validate the inputs. - * - * @param context the context - * @throws CLIException if the validation failed - */ - void setUp(ExecutionContext context) throws CLIException; - - /** - * Executes the command. - * - * @throws CLIException If anything went wrong. - */ - void run() throws CLIException; - - /** - * The command has been executed. Use this method to cleanup the environment. - * - * @throws CLIException if anything went wrong - */ - void tearDown() throws CLIException; - -} diff --git a/src/main/java/io/vertx/core/spi/launcher/CommandFactory.java b/src/main/java/io/vertx/core/spi/launcher/CommandFactory.java deleted file mode 100644 index 738a00e5e14..00000000000 --- a/src/main/java/io/vertx/core/spi/launcher/CommandFactory.java +++ /dev/null @@ -1,42 +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.spi.launcher; - -import io.vertx.core.Launcher; -import io.vertx.core.cli.CLI; -import io.vertx.core.cli.CommandLine; - -/** - * SPI Interface to provide a new {@link Launcher} command. Implementors needs to provide two methods: - *
    - *
  1. {@link #define()} - creates a {@link CLI} instance (so the model)
  2. - *
  3. {@link #create(CommandLine)}} - creates a new command instance
  4. - *
- * - * @author Clement Escoffier - */ -public interface CommandFactory { - - /** - * @return a new instance of the command. - */ - C create(CommandLine evaluated); - - /** - * Creates a new {@link CLI} instance. - * - * @return the CLI. - */ - CLI define(); - - -} diff --git a/src/main/java/io/vertx/core/spi/launcher/CommandFactoryLookup.java b/src/main/java/io/vertx/core/spi/launcher/CommandFactoryLookup.java deleted file mode 100644 index b51f6c46993..00000000000 --- a/src/main/java/io/vertx/core/spi/launcher/CommandFactoryLookup.java +++ /dev/null @@ -1,33 +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.spi.launcher; - -import io.vertx.core.impl.launcher.ServiceCommandFactoryLoader; - -import java.util.Collection; - -/** - * The interface to implement to look for commands. - * - * @see ServiceCommandFactoryLoader - * @author Clement Escoffier - */ -public interface CommandFactoryLookup { - - /** - * Looks for command implementation and instantiated them. - * - * @return the set of commands, empty if none are found. - */ - Collection> lookup(); - -} diff --git a/src/main/java/io/vertx/core/spi/launcher/DefaultCommand.java b/src/main/java/io/vertx/core/spi/launcher/DefaultCommand.java deleted file mode 100644 index fd9d5d20423..00000000000 --- a/src/main/java/io/vertx/core/spi/launcher/DefaultCommand.java +++ /dev/null @@ -1,116 +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.spi.launcher; - - -import io.vertx.core.cli.CLIException; -import io.vertx.core.cli.annotations.Description; -import io.vertx.core.cli.annotations.Hidden; -import io.vertx.core.cli.annotations.Option; - -import java.io.File; -import java.io.PrintStream; -import java.util.List; - -/** - * Default implementation of {@link Command} using annotation to define itself. It is highly recommended - * to extend this class when implementing a command. - *

- * It defines two hidden {@link Option}s to create system properties ({@code -Dkey=value}) and a way to - * configure the current working directory. - */ -public abstract class DefaultCommand implements Command { - - private File cwd; - protected List systemProperties; - - /** - * The execution context of the command. - */ - protected ExecutionContext executionContext; - - /** - * The {@link PrintStream} that the command can use to write on the console. - */ - protected PrintStream out; - - /** - * @return the configure current working directory. If not set use the "regular" Java current working - * directory. - */ - public File getCwd() { - return cwd != null ? cwd : new File("."); - } - - /** - * Sets the current working directory. This method is called when the user configure the "cwd" option as - * follows: {@code --cwd=the-directory}. - * - * @param cwd the directory - */ - @SuppressWarnings("unused") - @Option(longName = "cwd", argName = "dir") - @Description("Specifies the current working directory for this command, default set to the Java current directory") - @Hidden - public void setCwd(File cwd) { - this.cwd = cwd; - } - - /** - * Gets system properties passed in the user command line. The user can configure system properties using - * {@code -Dkey=value}. - * - * @param props the properties - */ - @SuppressWarnings("unused") - @Option(longName = "systemProperty", shortName = "D", argName = "key>= props) { - this.systemProperties = props; - } - - @Override - public void setUp(ExecutionContext ec) throws CLIException { - this.executionContext = ec; - this.out = executionContext.getPrintStream(); - applySystemProperties(); - } - - /** - * @return the print stream on which message should be written. - */ - public PrintStream out() { - return executionContext.getPrintStream(); - } - - @Override - public void tearDown() throws CLIException { - // Default implementation - does nothing. - } - - /** - * Sets the system properties specified by the user command line. - */ - protected void applySystemProperties() { - if (systemProperties != null) { - for (String prop : systemProperties) { - int p = prop.indexOf('='); - if (p > 0) { - String key = prop.substring(0, p); - String val = prop.substring(p + 1); - System.setProperty(key, val); - } - } - } - } -} diff --git a/src/main/java/io/vertx/core/spi/launcher/DefaultCommandFactory.java b/src/main/java/io/vertx/core/spi/launcher/DefaultCommandFactory.java deleted file mode 100644 index 54e14480b5b..00000000000 --- a/src/main/java/io/vertx/core/spi/launcher/DefaultCommandFactory.java +++ /dev/null @@ -1,70 +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.spi.launcher; - -import io.vertx.core.cli.CLI; -import io.vertx.core.cli.CommandLine; -import io.vertx.core.cli.annotations.CLIConfigurator; -import io.vertx.core.cli.impl.ReflectionUtils; - -import java.util.function.Supplier; - -/** - * Default implementation of {@link CommandFactory}. This implementation defines the {@link CLI} from the - * given {@link Command} implementation (by reading the annotation). Then, {@link Command} instance are - * created by calling an empty constructor on the given {@link Command} implementation. - * - * @author Clement Escoffier - */ -public class DefaultCommandFactory implements CommandFactory { - - private final Class clazz; - private final Supplier supplier; - - /** - * Creates a new {@link CommandFactory}. - * - * @param clazz the {@link Command} implementation - * @deprecated Please use {@link #DefaultCommandFactory(Class, Supplier)} - */ - @Deprecated - public DefaultCommandFactory(Class clazz) { - this(clazz, () -> ReflectionUtils.newInstance(clazz)); - } - - /** - * Creates a new {@link CommandFactory}. - * - * @param clazz the {@link Command} implementation - * @param supplier the {@link Command} implementation - */ - public DefaultCommandFactory(Class clazz, Supplier supplier) { - this.clazz = clazz; - this.supplier = supplier; - } - - /** - * @return a new instance of the command by invoking the default constructor of the given class. - */ - @Override - public C create(CommandLine cl) { - return supplier.get(); - } - - /** - * @return the {@link CLI} instance by reading the annotation. - */ - @Override - public CLI define() { - return CLIConfigurator.define(clazz); - } -} diff --git a/src/main/java/io/vertx/core/spi/launcher/ExecutionContext.java b/src/main/java/io/vertx/core/spi/launcher/ExecutionContext.java deleted file mode 100644 index 9287ff4a14f..00000000000 --- a/src/main/java/io/vertx/core/spi/launcher/ExecutionContext.java +++ /dev/null @@ -1,93 +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.spi.launcher; - -import io.vertx.core.cli.CLI; -import io.vertx.core.cli.CommandLine; -import io.vertx.core.impl.launcher.VertxCommandLauncher; - -import java.io.PrintStream; -import java.util.HashMap; - -/** - * The execution context contains various information on the execution. - */ -public class ExecutionContext extends HashMap { - private final VertxCommandLauncher launcher; - private final Command command; - private final CommandLine commandLine; - - /** - * Creates a new instance of {@link ExecutionContext}. - * - * @param command the command instance that is executed - * @param launcher the launcher class - * @param commandLine the command line - */ - public ExecutionContext(Command command, VertxCommandLauncher launcher, CommandLine commandLine) { - this.command = command; - this.commandLine = commandLine; - this.launcher = launcher; - } - - /** - * @return the command line object. - */ - public Command command() { - return command; - } - - /** - * @return the launcher. - */ - public VertxCommandLauncher launcher() { - return launcher; - } - - /** - * @return the {@link CLI}. - */ - public CLI cli() { - return commandLine.cli(); - } - - /** - * @return the {@link CommandLine}. - */ - public CommandLine commandLine() { - return commandLine; - } - - /** - * Executes another command. - * - * @param command the command name - * @param args the arguments - */ - public void execute(String command, String... args) { - launcher.execute(command, args); - } - - /** - * @return the {@code Main-Class} object. - */ - public Object main() { - return get("Main"); - } - - /** - * @return the {@link PrintStream} on which command can write. - */ - public PrintStream getPrintStream() { - return launcher.getPrintStream(); - } -} diff --git a/src/test/java/io/vertx/core/CustomerLauncherLowMemoryTest.java b/src/test/java/io/vertx/core/CustomerLauncherLowMemoryTest.java deleted file mode 100644 index b325a9fd85f..00000000000 --- a/src/test/java/io/vertx/core/CustomerLauncherLowMemoryTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2011-2022 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 org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - -import static io.vertx.test.core.AsyncTestBase.assertWaitUntil; - -public class CustomerLauncherLowMemoryTest { - - private static final String MSG_HOOK = CustomerLauncherLowMemoryTest.class.getSimpleName() + "-hook"; - - private Process process; - private File output; - - @Before - public void setUp() throws Exception { - output = File.createTempFile(CustomerLauncherLowMemoryTest.class.getSimpleName(), ".txt"); - output.deleteOnExit(); - } - - @After - public void tearDown() throws Exception { - if (process != null) { - process.destroyForcibly(); - } - } - - @Test - public void testCloseHookInvoked() throws Exception { - startExternalProcess(); - assertWaitUntil(() -> outputContains(MSG_HOOK), 10000, "Hook not invoked"); - stopExternalProcess(); - } - - private void startExternalProcess() throws IOException { - String javaHome = System.getProperty("java.home"); - String classpath = System.getProperty("java.class.path"); - - List command = new ArrayList<>(); - command.add(javaHome + File.separator + "bin" + File.separator + "java"); - command.add("-Xms100M"); - command.add("-Xmx100M"); - command.add("-classpath"); - command.add(classpath); - command.add(Launcher.class.getName()); - command.add("run"); - command.add(Verticle.class.getName()); - - process = new ProcessBuilder(command) - .redirectOutput(output) - .redirectErrorStream(true) - .start(); - } - - private void stopExternalProcess() throws InterruptedException { - AtomicBoolean stopped = new AtomicBoolean(); - new Thread(() -> { - try { - Thread.sleep(10_000); - } catch (InterruptedException ignore) { - return; - } - if (!stopped.get()) { - process.destroy(); - } - }); - process.waitFor(); - stopped.set(true); - } - - private boolean outputContains(String line) { - try { - return Files.readAllLines(output.toPath()).contains(line); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public static class Launcher extends io.vertx.core.Launcher { - - public static void main(String[] args) { - new Launcher().dispatch(args); - } - - @Override - public void beforeStoppingVertx(Vertx vertx) { - System.out.println(MSG_HOOK); - } - } - - public static class Verticle extends AbstractVerticle { - - private final Runtime runtime; - @SuppressWarnings("unused") - private List arrays; - - public Verticle() { - runtime = Runtime.getRuntime(); - } - - @Override - public void start() throws Exception { - vertx.>executeBlocking(() -> { - List res = new ArrayList<>(); - long l; - do { - res.add(new byte[5 * 1024]); - l = runtime.freeMemory(); - } while (l > 15 * 1024 * 1024); - runtime.gc(); - try { - Thread.sleep(100); - return res; - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw e; - } - }).onComplete(ar1 -> { - if (ar1.succeeded()) { - arrays = ar1.result(); - context.owner().close(); - } else { - ar1.cause().printStackTrace(); - } - }); - } - } -} diff --git a/src/test/java/io/vertx/core/IsolatingClassLoaderTest.java b/src/test/java/io/vertx/core/IsolatingClassLoaderTest.java deleted file mode 100644 index e73d7a7c915..00000000000 --- a/src/test/java/io/vertx/core/IsolatingClassLoaderTest.java +++ /dev/null @@ -1,137 +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.IsolatingClassLoader; -import io.vertx.core.json.JsonObject; -import org.junit.Before; -import org.junit.Test; - -import java.io.File; -import java.io.InputStream; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; -import java.util.Scanner; - -import static org.junit.Assert.*; - -/** - * Unit tests for {@link io.vertx.core.impl.IsolatingClassLoader} - */ -public class IsolatingClassLoaderTest { - - private String resourceName = "resource.json"; - private URL url1; - private URL url2; - private URL url3; - private URLClassLoader ucl; - private IsolatingClassLoader icl; - - @Before - public void setUp() throws Exception { - - String basePath = "src/test/resources/icl"; - - url1 = new File(basePath, "pkg1").toURI().toURL(); - url2 = new File(basePath, "pkg2").toURI().toURL(); - url3 = new File(basePath, "pkg3").toURI().toURL(); - - ucl = new URLClassLoader(new URL[]{url2, url3}); - icl = new IsolatingClassLoader(new URL[]{url1}, ucl, null); - - } - - @Test - public void testGetResource() throws Exception { - - URL resource = ucl.getResource(resourceName); - checkResource(url2, resource); - - resource = icl.getResource(resourceName); - checkResource(url1, resource); - - } - - @Test - public void testGetResourceNull() throws Exception { - - resourceName = "null_resource"; - URL resource = ucl.getResource(resourceName); - assertNull(resource); - - resource = icl.getResource(resourceName); - assertNull(resource); - - } - - @Test - public void testGetResources() throws Exception { - - Enumeration resources = ucl.getResources(resourceName); - List list = Collections.list(resources); - assertEquals(2, list.size()); - checkResource(url2, list.get(0)); - checkResource(url3, list.get(1)); - - resources = icl.getResources(resourceName); - list = Collections.list(resources); - assertEquals(3, list.size()); - checkResource(url1, list.get(0)); - checkResource(url2, list.get(1)); - checkResource(url3, list.get(2)); - - } - - private void checkResource(URL expected, URL resource) throws Exception { - assertEquals(expected.toString() + resourceName, resource.toString()); - } - - @Test - public void testGetResourcesNull() throws Exception { - - resourceName = "null_resource"; - Enumeration resources = ucl.getResources(resourceName); - List list = Collections.list(resources); - assertEquals(0, list.size()); - - resources = icl.getResources(resourceName); - list = Collections.list(resources); - assertEquals(0, list.size()); - - } - - @Test - public void testGetResourceAsStream() throws Exception { - - testGetResourceAsStream(2, ucl); - testGetResourceAsStream(1, icl); - - } - - private void testGetResourceAsStream(long ver, ClassLoader cl) throws Exception { - - try (InputStream is = cl.getResourceAsStream(resourceName)) { - assertNotNull(is); - - try (Scanner scanner = new Scanner(is, "UTF-8").useDelimiter("\\A")) { - assertTrue(scanner.hasNext()); - JsonObject json = new JsonObject(scanner.next()); - assertEquals(ver, json.getLong("ver", -1L).longValue()); - } - } - - } - -} diff --git a/src/test/java/io/vertx/core/LauncherTest.java b/src/test/java/io/vertx/core/LauncherTest.java deleted file mode 100644 index 77e640ae2df..00000000000 --- a/src/test/java/io/vertx/core/LauncherTest.java +++ /dev/null @@ -1,790 +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.commands.HelloCommand; -import io.vertx.core.impl.launcher.commands.RunCommand; -import io.vertx.core.impl.launcher.commands.VersionCommand; -import io.vertx.core.json.JsonObject; -import io.vertx.core.spi.metrics.MetricsOptionsTest; -import io.vertx.test.core.TestUtils; -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.*; -import java.net.URL; -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; - -public class LauncherTest extends VertxTestBase { - - private String expectedVersion; - private ByteArrayOutputStream out; - private PrintStream stream; - private Vertx vertx; - - @Override - public void setUp() throws Exception { - super.setUp(); - TestVerticle.instanceCount.set(0); - TestVerticle.processArgs = null; - TestVerticle.conf = null; - - // Read the expected version from the vertx=version.txt - final URL resource = this.getClass().getClassLoader().getResource("META-INF/vertx/vertx-version.txt"); - if (resource == null) { - throw new IllegalStateException("Cannot find the vertx-version.txt"); - } else { - try (BufferedReader in = new BufferedReader(new InputStreamReader(resource.openStream()))) { - expectedVersion = in.readLine(); - } - } - - Launcher.resetProcessArguments(); - - out = new ByteArrayOutputStream(); - stream = new PrintStream(out); - } - - @Override - public void tearDown() throws Exception { - clearProperties(); - super.tearDown(); - - out.close(); - stream.close(); - - if (vertx != null) { - vertx.close(); - } - } - - - @Test - public void testVersion() throws Exception { - String[] args = {"-version"}; - MyLauncher launcher = new MyLauncher(); - - launcher.dispatch(args); - - final VersionCommand version = (VersionCommand) launcher.getExistingCommandInstance("version"); - assertNotNull(version); - assertEquals(version.getVersion(), expectedVersion); - } - - @Test - public void testRunVerticleWithoutArgs() throws Exception { - MyLauncher launcher = new MyLauncher(); - String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName()}; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - assertEquals(Arrays.asList(args), TestVerticle.processArgs); - launcher.assertHooksInvoked(); - } - - @Test - public void testRunWithoutArgs() throws Exception { - MyLauncher launcher = new MyLauncher() { - @Override - public PrintStream getPrintStream() { - return stream; - } - }; - String[] args = {"run"}; - launcher.dispatch(args); - assertTrue(out.toString().contains("The argument 'main-verticle' is required")); - } - - @Test - public void testNoArgsAndNoMainVerticle() throws Exception { - MyLauncher launcher = new MyLauncher() { - @Override - public PrintStream getPrintStream() { - return stream; - } - }; - String[] args = {}; - launcher.dispatch(args); - assertTrue(out.toString().contains("Usage:")); - assertTrue(out.toString().contains("bare")); - assertTrue(out.toString().contains("run")); - assertTrue(out.toString().contains("hello")); - } - - @Test - public void testRunVerticle() throws Exception { - testRunVerticleMultiple(1); - } - - @Test - public void testRunVerticleMultipleInstances() throws Exception { - testRunVerticleMultiple(10); - } - - public void testRunVerticleMultiple(int instances) throws Exception { - MyLauncher launcher = new MyLauncher(); - String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName(), "-instances", String.valueOf(instances)}; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == instances); - assertEquals(Arrays.asList(args), TestVerticle.processArgs); - launcher.assertHooksInvoked(); - } - - @Test - public void testRunVerticleClustered() throws Exception { - MyLauncher launcher = new MyLauncher(); - String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName(), "-cluster"}; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - assertEquals(Arrays.asList(args), TestVerticle.processArgs); - launcher.assertHooksInvoked(); - } - - @Test - public void testRunVerticleHA() throws Exception { - MyLauncher launcher = new MyLauncher(); - String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName(), "-ha"}; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - assertEquals(Arrays.asList(args), TestVerticle.processArgs); - launcher.assertHooksInvoked(); - } - - @Test - public void testRunVerticleWithMainVerticleInManifestNoArgs() throws Exception { - // Copy the right manifest - File manifest = new File("target/test-classes/META-INF/MANIFEST-Launcher.MF"); - if (!manifest.isFile()) { - throw new IllegalStateException("Cannot find the MANIFEST-Launcher.MF file"); - } - File target = new File("target/test-classes/META-INF/MANIFEST.MF"); - Files.copy(manifest.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING); - - Launcher launcher = new Launcher(); - String[] args = new String[0]; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - assertEquals(Arrays.asList(args), TestVerticle.processArgs); - - cleanup(launcher); - } - - private void cleanup(Launcher launcher) { - RunCommand run = (RunCommand) launcher.getExistingCommandInstance("run"); - if (run != null) { - Vertx v = run.vertx(); - if (v != null) { - v.close(); - } - } - } - - @Test - public void testRunVerticleWithMainVerticleInManifestWithArgs() throws Exception { - // Copy the right manifest - File manifest = new File("target/test-classes/META-INF/MANIFEST-Launcher.MF"); - if (!manifest.isFile()) { - throw new IllegalStateException("Cannot find the MANIFEST-Launcher.MF file"); - } - File target = new File("target/test-classes/META-INF/MANIFEST.MF"); - Files.copy(manifest.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING); - - Launcher launcher = new Launcher(); - String[] args = {"-cluster", "-worker", "-instances=10"}; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 10); - assertEquals(Arrays.asList(args), TestVerticle.processArgs); - - cleanup(launcher); - } - - @Test - public void testRunVerticleWithMainVerticleInManifestWithCustomCommand() throws Exception { - // Copy the right manifest - File manifest = new File("target/test-classes/META-INF/MANIFEST-Launcher-hello.MF"); - if (!manifest.isFile()) { - throw new IllegalStateException("Cannot find the MANIFEST-Launcher-hello.MF file"); - } - File target = new File("target/test-classes/META-INF/MANIFEST.MF"); - Files.copy(manifest.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING); - - Launcher launcher = new Launcher(); - HelloCommand.called = false; - String[] args = {"--name=vert.x"}; - launcher.dispatch(args); - assertWaitUntil(() -> HelloCommand.called); - } - - @Test - public void testRunVerticleWithoutMainVerticleInManifestButWithCustomCommand() throws Exception { - // Copy the right manifest - File manifest = new File("target/test-classes/META-INF/MANIFEST-Launcher-Default-Command.MF"); - if (!manifest.isFile()) { - throw new IllegalStateException("Cannot find the MANIFEST-Default-Command.MF file"); - } - File target = new File("target/test-classes/META-INF/MANIFEST.MF"); - Files.copy(manifest.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING); - - Launcher launcher = new Launcher(); - HelloCommand.called = false; - String[] args = {"--name=vert.x"}; - launcher.dispatch(args); - assertWaitUntil(() -> HelloCommand.called); - } - - @Test - public void testRunWithOverriddenDefaultCommand() throws Exception { - // Copy the right manifest - File manifest = new File("target/test-classes/META-INF/MANIFEST-Launcher-hello.MF"); - if (!manifest.isFile()) { - throw new IllegalStateException("Cannot find the MANIFEST-Launcher-hello.MF file"); - } - File target = new File("target/test-classes/META-INF/MANIFEST.MF"); - Files.copy(manifest.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING); - - HelloCommand.called = false; - String[] args = {"run", TestVerticle.class.getName(), "--name=vert.x"}; - Launcher launcher = new Launcher(); - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - - cleanup(launcher); - } - - @Test - public void testRunWithOverriddenDefaultCommandRequiringArgs() throws Exception { - // Copy the right manifest - File manifest = new File("target/test-classes/META-INF/MANIFEST-Launcher-run.MF"); - if (!manifest.isFile()) { - throw new IllegalStateException("Cannot find the MANIFEST-Launcher-run.MF file"); - } - File target = new File("target/test-classes/META-INF/MANIFEST.MF"); - Files.copy(manifest.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING); - - String[] args = {TestVerticle.class.getName()}; - Launcher launcher = new Launcher(); - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - - cleanup(launcher); - } - - - @Test - public void testRunVerticleWithExtendedMainVerticleNoArgs() throws Exception { - MySecondLauncher launcher = new MySecondLauncher(); - String[] args = new String[0]; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - assertEquals(Arrays.asList(args), TestVerticle.processArgs); - } - - @Test - public void testRunVerticleWithExtendedMainVerticleWithArgs() throws Exception { - MySecondLauncher launcher = new MySecondLauncher(); - String[] args = {"-cluster", "-worker"}; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - assertEquals(Arrays.asList(args), TestVerticle.processArgs); - } - - @Test - public void testFatJarWithHelp() throws Exception { - // Copy the right manifest - File manifest = new File("target/test-classes/META-INF/MANIFEST-Launcher.MF"); - if (!manifest.isFile()) { - throw new IllegalStateException("Cannot find the MANIFEST-Launcher.MF file"); - } - File target = new File("target/test-classes/META-INF/MANIFEST.MF"); - Files.copy(manifest.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING); - - Launcher launcher = new Launcher() { - @Override - public PrintStream getPrintStream() { - return stream; - } - }; - - String[] args = {"--help"}; - launcher.dispatch(args); - assertTrue(out.toString().contains("Usage")); - assertTrue(out.toString().contains("run")); - assertTrue(out.toString().contains("version")); - assertTrue(out.toString().contains("bare")); - } - - @Test - public void testFatJarWithCommandHelp() throws Exception { - // Copy the right manifest - File manifest = new File("target/test-classes/META-INF/MANIFEST-Launcher.MF"); - if (!manifest.isFile()) { - throw new IllegalStateException("Cannot find the MANIFEST-Launcher.MF file"); - } - File target = new File("target/test-classes/META-INF/MANIFEST.MF"); - Files.copy(manifest.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING); - - Launcher launcher = new Launcher() { - @Override - public PrintStream getPrintStream() { - return stream; - } - }; - String[] args = {"hello", "--help"}; - launcher.dispatch(args); - assertTrue(out.toString().contains("Usage")); - assertTrue(out.toString().contains("hello")); - assertTrue(out.toString().contains("A simple command to wish you a good day.")); // Description text. - } - - @Test - public void testFatJarWithMissingCommandHelp() throws Exception { - // Copy the right manifest - File manifest = new File("target/test-classes/META-INF/MANIFEST-Launcher.MF"); - if (!manifest.isFile()) { - throw new IllegalStateException("Cannot find the MANIFEST-Launcher.MF file"); - } - File target = new File("target/test-classes/META-INF/MANIFEST.MF"); - Files.copy(manifest.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING); - - Launcher launcher = new Launcher() { - @Override - public PrintStream getPrintStream() { - return stream; - } - }; - String[] args = {"not-a-command", "--help"}; - launcher.dispatch(args); - assertTrue(out.toString().contains("The command 'not-a-command' is not a valid command.")); - } - - @Test - public void testRunVerticleWithConfString() throws Exception { - MyLauncher launcher = new MyLauncher(); - JsonObject conf = new JsonObject().put("foo", "bar").put("wibble", 123); - String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName(), "-conf", conf.encode()}; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - assertEquals(conf, TestVerticle.conf); - } - - @Rule - public TemporaryFolder testFolder = new TemporaryFolder(); - - - @Test - public void testRunVerticleWithConfFile() throws Exception { - Path tempDir = testFolder.newFolder().toPath(); - Path tempFile = Files.createTempFile(tempDir, "conf", "json"); - MyLauncher launcher = new MyLauncher(); - 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()}; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - assertEquals(conf, TestVerticle.conf); - } - - @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(RunCommand.VERTX_OPTIONS_PROP_PREFIX + "eventLoopPoolSize", "123"); - System.setProperty(RunCommand.VERTX_OPTIONS_PROP_PREFIX + "maxEventLoopExecuteTime", "123767667"); - System.setProperty(RunCommand.METRICS_OPTIONS_PROP_PREFIX + "enabled", "true"); - System.setProperty(RunCommand.VERTX_OPTIONS_PROP_PREFIX + "haGroup", "somegroup"); - System.setProperty(RunCommand.VERTX_OPTIONS_PROP_PREFIX + "maxEventLoopExecuteTimeUnit", "SECONDS"); - - MyLauncher launcher = new MyLauncher(); - String[] args; - if (clustered) { - args = new String[]{"run", "java:" + TestVerticle.class.getCanonicalName(), "-cluster"}; - } else { - args = new String[]{"run", "java:" + TestVerticle.class.getCanonicalName()}; - } - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - - VertxOptions opts = launcher.getVertxOptions(); - - assertEquals(123, opts.getEventLoopPoolSize(), 0); - assertEquals(123767667L, opts.getMaxEventLoopExecuteTime()); - assertEquals(true, opts.getMetricsOptions().isEnabled()); - assertEquals("somegroup", opts.getHAGroup()); - assertEquals(TimeUnit.SECONDS, opts.getMaxEventLoopExecuteTimeUnit()); - } - - private void clearProperties() { - Set 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); - } - } - toClear.forEach(System::clearProperty); - } - - @Test - public void testConfigureFromJsonFile() throws Exception { - testConfigureFromJson(true); - } - - @Test - public void testConfigureFromJsonString() throws Exception { - testConfigureFromJson(false); - } - - private void testConfigureFromJson(boolean jsonFile) throws Exception { - JsonObject json = new JsonObject() - .put("eventLoopPoolSize", 123) - .put("maxEventLoopExecuteTime", 123767667) - .put("metricsOptions", new JsonObject().put("enabled", true)) - .put("eventBusOptions", new JsonObject().put("clusterPublicHost", "mars")) - .put("haGroup", "somegroup") - .put("maxEventLoopExecuteTimeUnit", "SECONDS"); - - String optionsArg; - if (jsonFile) { - File file = testFolder.newFile(); - Files.write(file.toPath(), json.toBuffer().getBytes()); - optionsArg = file.getPath(); - } else { - optionsArg = json.toString(); - } - - MyLauncher launcher = new MyLauncher(); - String[] args = new String[]{"run", "java:" + TestVerticle.class.getCanonicalName(), "-options", optionsArg}; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - - VertxOptions opts = launcher.getVertxOptions(); - - assertEquals(123, opts.getEventLoopPoolSize(), 0); - assertEquals(123767667L, opts.getMaxEventLoopExecuteTime()); - assertEquals(true, opts.getMetricsOptions().isEnabled()); - assertEquals("mars", opts.getEventBusOptions().getClusterPublicHost()); - assertEquals("somegroup", opts.getHAGroup()); - assertEquals(TimeUnit.SECONDS, opts.getMaxEventLoopExecuteTimeUnit()); - } - - @Test - public void testCustomMetricsOptions() throws Exception { - System.setProperty(RunCommand.METRICS_OPTIONS_PROP_PREFIX + "enabled", "true"); - System.setProperty(RunCommand.METRICS_OPTIONS_PROP_PREFIX + "customProperty", "customPropertyValue"); - MyLauncher launcher = new MyLauncher(); - String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName()}; - ClassLoader oldCL = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(MetricsOptionsTest.createMetricsFromMetaInfLoader("io.vertx.core.CustomMetricsFactory")); - try { - launcher.dispatch(args); - } finally { - Thread.currentThread().setContextClassLoader(oldCL); - } - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - VertxOptions opts = launcher.getVertxOptions(); - CustomMetricsOptions custom = (CustomMetricsOptions) opts.getMetricsOptions(); - assertEquals("customPropertyValue", custom.getCustomProperty()); - assertTrue(launcher.getVertx().isMetricsEnabled()); - } - - @Test - public void testConfigureFromSystemPropertiesInvalidPropertyName() throws Exception { - - System.setProperty(RunCommand.VERTX_OPTIONS_PROP_PREFIX + "nosuchproperty", "123"); - - // Should be ignored - - MyLauncher launcher = new MyLauncher(); - String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName()}; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - - VertxOptions opts = launcher.getVertxOptions(); - VertxOptions def = new VertxOptions(); - if (opts.getMetricsOptions().isEnabled()) { - def.getMetricsOptions().setEnabled(true); - } - assertEquals(def.toJson(), opts.toJson()); - - } - - @Test - public void testConfigureFromSystemPropertiesInvalidPropertyType() throws Exception { - // One for each type that we support - System.setProperty(RunCommand.VERTX_OPTIONS_PROP_PREFIX + "eventLoopPoolSize", "sausages"); - // Should be ignored - - MyLauncher launcher = new MyLauncher(); - String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName()}; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - - VertxOptions opts = launcher.getVertxOptions(); - VertxOptions def = new VertxOptions(); - if (opts.getMetricsOptions().isEnabled()) { - def.getMetricsOptions().setEnabled(true); - } - assertEquals(def.toJson(), opts.toJson()); - } - - @Test - public void testCustomMetricsOptionsFromJsonFile() throws Exception { - testCustomMetricsOptionsFromJson(true); - } - - @Test - public void testCustomMetricsOptionsFromJsonString() throws Exception { - testCustomMetricsOptionsFromJson(false); - } - - private void testCustomMetricsOptionsFromJson(boolean jsonFile) throws Exception { - JsonObject json = new JsonObject() - .put("metricsOptions", new JsonObject() - .put("enabled", true) - .put("customProperty", "customPropertyValue") - .put("nestedOptions", new JsonObject().put("nestedProperty", "nestedValue"))); - - String optionsArg; - if (jsonFile) { - File file = testFolder.newFile(); - Files.write(file.toPath(), json.toBuffer().getBytes()); - optionsArg = file.getPath(); - } else { - optionsArg = json.toString(); - } - - MyLauncher launcher = new MyLauncher(); - String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName(), "-options", optionsArg}; - ClassLoader oldCL = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(MetricsOptionsTest.createMetricsFromMetaInfLoader("io.vertx.core.CustomMetricsFactory")); - try { - launcher.dispatch(args); - } finally { - Thread.currentThread().setContextClassLoader(oldCL); - } - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - - VertxOptions opts = launcher.getVertxOptions(); - CustomMetricsOptions custom = (CustomMetricsOptions) opts.getMetricsOptions(); - assertEquals("customPropertyValue", custom.getCustomProperty()); - assertEquals("nestedValue", custom.getNestedOptions().getNestedProperty()); - } - - @Test - public void testWhenPassingTheMainObject() throws Exception { - MyLauncher launcher = new MyLauncher(); - int instances = 10; - launcher.dispatch(launcher, new String[]{"run", "java:" + TestVerticle.class.getCanonicalName(), - "-instances", "10"}); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == instances); - } - - @Test - public void testBare() throws Exception { - MyLauncher launcher = new MyLauncher(); - launcher.dispatch(new String[]{"bare"}); - assertWaitUntil(() -> launcher.afterStartingVertxInvoked); - } - - @Test - public void testBareAlias() throws Exception { - MyLauncher launcher = new MyLauncher(); - launcher.dispatch(new String[]{"-ha"}); - assertWaitUntil(() -> launcher.afterStartingVertxInvoked); - } - - @Test - public void testConfigureClusterHostPortFromProperties() throws Exception { - int clusterPort = TestUtils.randomHighPortInt(); - System.setProperty(RunCommand.VERTX_EVENTBUS_PROP_PREFIX + "host", "127.0.0.1"); - System.setProperty(RunCommand.VERTX_EVENTBUS_PROP_PREFIX + "port", Integer.toString(clusterPort)); - MyLauncher launcher = new MyLauncher(); - String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName(), "-cluster"}; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - assertEquals("127.0.0.1", launcher.options.getEventBusOptions().getHost()); - assertEquals(clusterPort, launcher.options.getEventBusOptions().getPort()); - assertNull(launcher.options.getEventBusOptions().getClusterPublicHost()); - assertEquals(-1, launcher.options.getEventBusOptions().getClusterPublicPort()); - } - - @Test - public void testConfigureClusterHostPortFromCommandLine() throws Exception { - int clusterPort = TestUtils.randomHighPortInt(); - MyLauncher launcher = new MyLauncher(); - String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName(), "-cluster", "--cluster-host", "127.0.0.1", "--cluster-port", Integer.toString(clusterPort)}; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - assertEquals("127.0.0.1", launcher.options.getEventBusOptions().getHost()); - assertEquals(clusterPort, launcher.options.getEventBusOptions().getPort()); - assertNull(launcher.options.getEventBusOptions().getClusterPublicHost()); - assertEquals(-1, launcher.options.getEventBusOptions().getClusterPublicPort()); - } - - @Test - public void testConfigureClusterPublicHostPortFromCommandLine() throws Exception { - int clusterPublicPort = TestUtils.randomHighPortInt(); - MyLauncher launcher = new MyLauncher(); - String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName(), "-cluster", "--cluster-public-host", "127.0.0.1", "--cluster-public-port", Integer.toString(clusterPublicPort)}; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - assertEquals("127.0.0.1", launcher.options.getEventBusOptions().getClusterPublicHost()); - assertEquals(clusterPublicPort, launcher.options.getEventBusOptions().getClusterPublicPort()); - } - - @Test - public void testOverrideClusterHostPortFromProperties() throws Exception { - int clusterPort = TestUtils.randomHighPortInt(); - int newClusterPort = TestUtils.randomHighPortInt(); - int newClusterPublicPort = TestUtils.randomHighPortInt(); - System.setProperty(RunCommand.VERTX_OPTIONS_PROP_PREFIX + "clusterHost", "127.0.0.2"); - System.setProperty(RunCommand.VERTX_OPTIONS_PROP_PREFIX + "clusterPort", Integer.toString(clusterPort)); - MyLauncher launcher = new MyLauncher(); - launcher.clusterHost = "127.0.0.1"; - launcher.clusterPort = newClusterPort; - launcher.clusterPublicHost = "127.0.0.3"; - launcher.clusterPublicPort = newClusterPublicPort; - String[] args = {"run", "java:" + TestVerticle.class.getCanonicalName(), "-cluster"}; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - assertEquals("127.0.0.1", launcher.options.getEventBusOptions().getHost()); - assertEquals(newClusterPort, launcher.options.getEventBusOptions().getPort()); - assertEquals("127.0.0.3", launcher.options.getEventBusOptions().getClusterPublicHost()); - assertEquals(newClusterPublicPort, launcher.options.getEventBusOptions().getClusterPublicPort()); - } - - @Test - public void testOverrideClusterHostPortFromCommandLine() throws Exception { - int clusterPort = TestUtils.randomHighPortInt(); - int clusterPublicPort = TestUtils.randomHighPortInt(); - int newClusterPort = TestUtils.randomHighPortInt(); - int newClusterPublicPort = TestUtils.randomHighPortInt(); - MyLauncher launcher = new MyLauncher(); - launcher.clusterHost = "127.0.0.1"; - launcher.clusterPort = newClusterPort; - launcher.clusterPublicHost = "127.0.0.3"; - launcher.clusterPublicPort = newClusterPublicPort; - String[] args = { - "run", "java:" + TestVerticle.class.getCanonicalName(), - "-cluster", - "--cluster-host", "127.0.0.2", "--cluster-port", Integer.toString(clusterPort), - "--cluster-public-host", "127.0.0.4", "--cluster-public-port", Integer.toString(clusterPublicPort) - }; - launcher.dispatch(args); - assertWaitUntil(() -> TestVerticle.instanceCount.get() == 1); - assertEquals("127.0.0.1", launcher.options.getEventBusOptions().getHost()); - assertEquals(newClusterPort, launcher.options.getEventBusOptions().getPort()); - assertEquals("127.0.0.3", launcher.options.getEventBusOptions().getClusterPublicHost()); - assertEquals(newClusterPublicPort, launcher.options.getEventBusOptions().getClusterPublicPort()); - } - - class MyLauncher extends Launcher { - boolean afterConfigParsed = false; - boolean beforeStartingVertxInvoked = false; - boolean afterStartingVertxInvoked = false; - boolean beforeDeployingVerticle = false; - - VertxOptions options; - DeploymentOptions deploymentOptions; - JsonObject config; - String clusterHost; - int clusterPort; - String clusterPublicHost; - int clusterPublicPort; - - PrintStream stream = new PrintStream(out); - - /** - * @return the printer used to write the messages. Defaults to {@link System#out}. - */ - @Override - public PrintStream getPrintStream() { - return stream; - } - - public Vertx getVertx() { - return vertx; - } - - public VertxOptions getVertxOptions() { - return options; - } - - @Override - public void afterConfigParsed(JsonObject config) { - afterConfigParsed = true; - this.config = config; - } - - @Override - public void beforeStartingVertx(VertxOptions options) { - beforeStartingVertxInvoked = true; - this.options = options; - if (clusterHost != null) { - options.getEventBusOptions() - .setHost(clusterHost) - .setPort(clusterPort) - .setClusterPublicHost(clusterPublicHost) - .setClusterPublicPort(clusterPublicPort); - super.beforeStartingVertx(options); - } - } - - @Override - public void afterStartingVertx(Vertx vertx) { - afterStartingVertxInvoked = true; - LauncherTest.this.vertx = vertx; - } - - @Override - public void beforeDeployingVerticle(DeploymentOptions deploymentOptions) { - beforeDeployingVerticle = true; - this.deploymentOptions = deploymentOptions; - } - - public void assertHooksInvoked() { - assertTrue(afterConfigParsed); - assertTrue(beforeStartingVertxInvoked); - assertTrue(afterStartingVertxInvoked); - assertTrue(beforeDeployingVerticle); - assertNotNull(vertx); - } - } - - class MySecondLauncher extends MyLauncher { - - @Override - public String getMainVerticle() { - return "java:io.vertx.test.verticles.TestVerticle"; - } - } -} diff --git a/src/test/java/io/vertx/core/cli/AmbiguousOptionExceptionTest.java b/src/test/java/io/vertx/core/cli/AmbiguousOptionExceptionTest.java deleted file mode 100644 index ed06a4ec7f7..00000000000 --- a/src/test/java/io/vertx/core/cli/AmbiguousOptionExceptionTest.java +++ /dev/null @@ -1,37 +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.cli; - -import org.junit.Test; - -import java.util.Arrays; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Test the {@link AmbiguousOptionException}. - */ -public class AmbiguousOptionExceptionTest { - - @Test - public void testCreation() { - AmbiguousOptionException exception = new AmbiguousOptionException("foo", - Arrays.asList(new Option().setLongName("foobar"), new Option().setLongName("foobaz"))); - assertThat(exception.getOptions()).hasSize(2); - assertThat(exception.getToken()).isEqualTo("foo"); - assertThat(exception.getMessage()) - .contains("Ambiguous argument in command line") - .contains("'foo'") - .contains("foobar").contains("foobaz"); - } - -} diff --git a/src/test/java/io/vertx/core/cli/OptionTest.java b/src/test/java/io/vertx/core/cli/OptionTest.java deleted file mode 100644 index 334873bcbfa..00000000000 --- a/src/test/java/io/vertx/core/cli/OptionTest.java +++ /dev/null @@ -1,67 +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.cli; - -import io.vertx.test.core.TestUtils; -import io.vertx.test.core.VertxTestBase; -import org.junit.Test; - -/** - * @author Ruslan Sennov - */ -public class OptionTest extends VertxTestBase { - - @Test - public void createAndCopy() { - Option option = new Option() - .setArgName(TestUtils.randomAlphaString(100)) - .addChoice(TestUtils.randomAlphaString(100)) - .setDefaultValue(TestUtils.randomAlphaString(100)) - .setDescription(TestUtils.randomAlphaString(100)) - .setFlag(TestUtils.randomBoolean()) - .setHelp(TestUtils.randomBoolean()) - .setHidden(TestUtils.randomBoolean()) - .setLongName(TestUtils.randomAlphaString(100)) - .setMultiValued(TestUtils.randomBoolean()) - .setRequired(TestUtils.randomBoolean()) - .setShortName(TestUtils.randomAlphaString(100)) - .setSingleValued(TestUtils.randomBoolean()); - - Option copy = new Option(option); - assertEquals(copy.getArgName(), option.getArgName()); - assertEquals(copy.getChoices(), option.getChoices()); - assertEquals(copy.getDefaultValue(), option.getDefaultValue()); - assertEquals(copy.getDescription(), option.getDescription()); - assertEquals(copy.isFlag(), option.isFlag()); - assertEquals(copy.isHelp(), option.isHelp()); - assertEquals(copy.isHidden(), option.isHidden()); - assertEquals(copy.getLongName(), option.getLongName()); - assertEquals(copy.isMultiValued(), option.isMultiValued()); - assertEquals(copy.isRequired(), option.isRequired()); - assertEquals(copy.getShortName(), option.getShortName()); - assertEquals(copy.isSingleValued(), option.isSingleValued()); - - copy = new Option(option.toJson()); - assertEquals(copy.getArgName(), option.getArgName()); - assertEquals(copy.getChoices(), option.getChoices()); - assertEquals(copy.getDefaultValue(), option.getDefaultValue()); - assertEquals(copy.getDescription(), option.getDescription()); - assertEquals(copy.isFlag(), option.isFlag()); - assertEquals(copy.isHelp(), option.isHelp()); - assertEquals(copy.isHidden(), option.isHidden()); - assertEquals(copy.getLongName(), option.getLongName()); - assertEquals(copy.isMultiValued(), option.isMultiValued()); - assertEquals(copy.isRequired(), option.isRequired()); - assertEquals(copy.getShortName(), option.getShortName()); - assertEquals(copy.isSingleValued(), option.isSingleValued()); - } -} diff --git a/src/test/java/io/vertx/core/cli/converters/BooleanConverterTest.java b/src/test/java/io/vertx/core/cli/converters/BooleanConverterTest.java deleted file mode 100644 index 43a2e912cf7..00000000000 --- a/src/test/java/io/vertx/core/cli/converters/BooleanConverterTest.java +++ /dev/null @@ -1,66 +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.cli.converters; - -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - - -public class BooleanConverterTest { - - private BooleanConverter converter = BooleanConverter.INSTANCE; - - @Test - public void testYesNo() throws Exception { - assertThat(converter.fromString("yes")).isTrue(); - assertThat(converter.fromString("YeS")).isTrue(); - assertThat(converter.fromString("no")).isFalse(); - assertThat(converter.fromString("nO")).isFalse(); - } - - @Test - public void testOnOff() throws Exception { - assertThat(converter.fromString("on")).isTrue(); - assertThat(converter.fromString("ON")).isTrue(); - assertThat(converter.fromString("off")).isFalse(); - assertThat(converter.fromString("oFf")).isFalse(); - } - - @Test - public void testTrueFalse() throws Exception { - assertThat(converter.fromString("true")).isTrue(); - assertThat(converter.fromString("TruE")).isTrue(); - assertThat(converter.fromString("fALse")).isFalse(); - assertThat(converter.fromString("false")).isFalse(); - } - - @Test - public void testNumbers() throws Exception { - assertThat(converter.fromString("1")).isTrue(); - assertThat(converter.fromString("2")).isFalse(); - assertThat(converter.fromString("0")).isFalse(); - } - - @Test - public void testWithNullAndEmptyString() throws Exception { - assertThat(converter.fromString(null)).isFalse(); - assertThat(converter.fromString("")).isFalse(); - } - - @Test - public void testWithRandomString() throws Exception { - assertThat(converter.fromString("aaaa")).isFalse(); - assertThat(converter.fromString("welcome true")).isFalse(); - assertThat(converter.fromString("true welcome")).isFalse(); - } -} diff --git a/src/test/java/io/vertx/core/cli/converters/CharacterConverterTest.java b/src/test/java/io/vertx/core/cli/converters/CharacterConverterTest.java deleted file mode 100644 index 88268d429c9..00000000000 --- a/src/test/java/io/vertx/core/cli/converters/CharacterConverterTest.java +++ /dev/null @@ -1,42 +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.cli.converters; - -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - - -public class CharacterConverterTest { - - CharacterConverter converter = CharacterConverter.INSTANCE; - - @Test - public void testFromString() throws Exception { - assertThat(converter.fromString("a")).isEqualTo('a'); - } - - @Test(expected = NullPointerException.class) - public void testWithNull() throws Exception { - converter.fromString(null); - } - - @Test(expected = IllegalArgumentException.class) - public void testWithEmptyString() throws Exception { - converter.fromString(""); - } - - @Test(expected = IllegalArgumentException.class) - public void testWithLongString() throws Exception { - converter.fromString("ab"); - } -} diff --git a/src/test/java/io/vertx/core/cli/converters/ConstructorBasedConverterTest.java b/src/test/java/io/vertx/core/cli/converters/ConstructorBasedConverterTest.java deleted file mode 100644 index 4f84678aac8..00000000000 --- a/src/test/java/io/vertx/core/cli/converters/ConstructorBasedConverterTest.java +++ /dev/null @@ -1,32 +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.cli.converters; - -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - - -public class ConstructorBasedConverterTest { - - - @Test - public void testGetIfEligible() throws Exception { - assertThat(ConstructorBasedConverter.getIfEligible(Person.class)).isNotNull(); - assertThat(ConstructorBasedConverter.getIfEligible(Object.class)).isNull(); - } - - @Test - public void testFromString() throws Exception { - assertThat(ConstructorBasedConverter.getIfEligible(Person.class).fromString("vertx").name).isEqualTo("vertx"); - } -} diff --git a/src/test/java/io/vertx/core/cli/converters/ConvertersTest.java b/src/test/java/io/vertx/core/cli/converters/ConvertersTest.java deleted file mode 100644 index 26959389520..00000000000 --- a/src/test/java/io/vertx/core/cli/converters/ConvertersTest.java +++ /dev/null @@ -1,111 +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.cli.converters; - -import org.junit.Test; - -import java.io.File; -import java.net.URL; -import java.util.NoSuchElementException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; - - -public class ConvertersTest { - - @Test - public void testCreatingSingleValueUsingValueOfOnEnumeration() { - assertThat(Converters.create(HttpMethod.class, "GET")).isEqualTo(HttpMethod.GET); - try { - assertThat(Converters.create(HttpMethod.class, null)).isNull(); - fail("Exception expected"); - } catch (IllegalArgumentException e) { - // OK. - } - - // Invalid value - try { - assertThat(Converters.create(HttpMethod.class, "FOO_IS_NOT_A_METHOD")).isNull(); - fail("Exception expected"); - } catch (IllegalArgumentException e) { - // OK. - } - } - - @Test - public void testWithString() throws NoSuchMethodException { - assertThat(Converters.create(String.class, "Hello")).isEqualTo("Hello"); - assertThat(Converters.create(String.class, "")).isEqualTo(""); - } - - @Test - public void testWithPrimitives() throws NoSuchMethodException { - assertThat(Converters.create(Integer.class, "1")).isEqualTo(1); - assertThat(Converters.create(Integer.TYPE, "1")).isEqualTo(1); - - assertThat(Converters.create(Long.class, "2")).isEqualTo(2l); - assertThat(Converters.create(Long.TYPE, "2")).isEqualTo(2l); - - assertThat(Converters.create(Short.class, "3")).isEqualTo((short) 3); - assertThat(Converters.create(Short.TYPE, "3")).isEqualTo((short) 3); - - assertThat(Converters.create(Byte.class, "4")).isEqualTo((byte) 4); - assertThat(Converters.create(Byte.TYPE, "4")).isEqualTo((byte) 4); - - assertThat(Converters.create(Float.class, "5.5")).isEqualTo(5.5f); - assertThat(Converters.create(Float.TYPE, "5.5")).isEqualTo(5.5f); - - assertThat(Converters.create(Double.class, "5.5")).isEqualTo(5.5d); - assertThat(Converters.create(Double.TYPE, "5.5")).isEqualTo(5.5d); - - assertThat(Converters.create(Character.class, "a")).isEqualTo('a'); - assertThat(Converters.create(Character.TYPE, "a")).isEqualTo('a'); - - assertThat(Converters.create(Boolean.class, "true")).isTrue(); - assertThat(Converters.create(Boolean.TYPE, "on")).isTrue(); - assertThat(Converters.create(Boolean.class, "")).isFalse(); - } - - @Test - public void testUsingFrom() throws NoSuchMethodException { - assertThat(Converters.create(Person2.class, "vertx").name).isEqualTo("vertx"); - } - - @Test - public void testUsingFromString() throws NoSuchMethodException { - assertThat(Converters.create(Person3.class, "vertx").name).isEqualTo("vertx"); - } - - @Test(expected = NoSuchElementException.class) - public void testMissingConvertion() throws NoSuchMethodException { - Converters.create(Object.class, "hello"); - } - - @Test - public void testWithURL() { - final URL url = Converters.create(URL.class, "http://vertx.io"); - assertThat(url.toExternalForm()).isEqualToIgnoringCase("http://vertx.io"); - } - - @Test - public void testWithFile() { - final File file = Converters.create(File.class, "foo/hello.txt"); - assertThat(file).hasName("hello.txt") - .doesNotExist(); - } - - private enum HttpMethod { - GET - } - -} diff --git a/src/test/java/io/vertx/core/cli/converters/CustomConverterTest.java b/src/test/java/io/vertx/core/cli/converters/CustomConverterTest.java deleted file mode 100644 index c307f5338f9..00000000000 --- a/src/test/java/io/vertx/core/cli/converters/CustomConverterTest.java +++ /dev/null @@ -1,34 +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.cli.converters; - -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - - -public class CustomConverterTest { - - @Test - public void testCreation() { - assertThat(new Person4Converter().fromString("bob, morane").first).isEqualToIgnoringCase("bob"); - assertThat(new Person4Converter().fromString("bob, morane").last).isEqualToIgnoringCase("morane"); - } - - @Test - public void testConvertion() { - Person4 p4 = Converters.create("bob, morane", new Person4Converter()); - assertThat(p4.first).isEqualTo("bob"); - assertThat(p4.last).isEqualTo("morane"); - } - -} diff --git a/src/test/java/io/vertx/core/cli/converters/Person.java b/src/test/java/io/vertx/core/cli/converters/Person.java deleted file mode 100644 index d54ca912152..00000000000 --- a/src/test/java/io/vertx/core/cli/converters/Person.java +++ /dev/null @@ -1,27 +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.cli.converters; - - -public class Person { - - public final String name; - - /** - * A constructor that can be used by the engine. - * - * @param n the name - */ - public Person(String n) { - this.name = n; - } -} diff --git a/src/test/java/io/vertx/core/cli/converters/Person2.java b/src/test/java/io/vertx/core/cli/converters/Person2.java deleted file mode 100644 index 0c2e3da1e51..00000000000 --- a/src/test/java/io/vertx/core/cli/converters/Person2.java +++ /dev/null @@ -1,26 +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.cli.converters; - - -public class Person2 { - - public final String name; - - private Person2(String n) { - this.name = n; - } - - public static Person2 from(String n) { - return new Person2(n); - } -} diff --git a/src/test/java/io/vertx/core/cli/converters/Person3.java b/src/test/java/io/vertx/core/cli/converters/Person3.java deleted file mode 100644 index dcbea9655f3..00000000000 --- a/src/test/java/io/vertx/core/cli/converters/Person3.java +++ /dev/null @@ -1,26 +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.cli.converters; - - -public class Person3 { - - public final String name; - - private Person3(String n) { - this.name = n; - } - - public static Person3 fromString(String n) { - return new Person3(n); - } -} diff --git a/src/test/java/io/vertx/core/cli/converters/Person4.java b/src/test/java/io/vertx/core/cli/converters/Person4.java deleted file mode 100644 index 1cb96a0a562..00000000000 --- a/src/test/java/io/vertx/core/cli/converters/Person4.java +++ /dev/null @@ -1,24 +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.cli.converters; - - -public class Person4 { - - public final String first; - public final String last; - - public Person4(String f, String l) { - this.first = f; - this.last = l; - } -} diff --git a/src/test/java/io/vertx/core/cli/converters/Person4Converter.java b/src/test/java/io/vertx/core/cli/converters/Person4Converter.java deleted file mode 100644 index 163ae4358ad..00000000000 --- a/src/test/java/io/vertx/core/cli/converters/Person4Converter.java +++ /dev/null @@ -1,21 +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.cli.converters; - - -public class Person4Converter implements Converter { - @Override - public Person4 fromString(String s) { - final String[] strings = s.split(","); - return new Person4(strings[0].trim(), strings[1].trim()); - } -} diff --git a/src/test/java/io/vertx/core/cli/impl/CLIConfiguratorTest.java b/src/test/java/io/vertx/core/cli/impl/CLIConfiguratorTest.java deleted file mode 100644 index a3c3de883aa..00000000000 --- a/src/test/java/io/vertx/core/cli/impl/CLIConfiguratorTest.java +++ /dev/null @@ -1,623 +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.cli.impl; - - -import io.vertx.core.cli.*; -import io.vertx.core.cli.Option; -import io.vertx.core.cli.annotations.Argument; -import io.vertx.core.cli.annotations.*; -import io.vertx.core.cli.converters.*; -import org.junit.Test; - -import java.util.*; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Fail.fail; - -public class CLIConfiguratorTest { - - @Test - public void testHelloCLIFromClass() { - CLI command = CLIConfigurator.define(HelloClI.class); - - assertThat(command.getOptions()).hasSize(1); - TypedOption option = (TypedOption) find(command.getOptions(), "name"); - assertThat(option.getLongName()).isEqualToIgnoringCase("name"); - assertThat(option.getShortName()).isEqualToIgnoringCase("n"); - assertThat(option.getType()).isEqualTo(String.class); - assertThat(option.getArgName()).isEqualTo("name"); - assertThat(option.getDescription()).isEqualToIgnoringCase("your name"); - assertThat(option.getDefaultValue()).isNull(); - assertThat(option.acceptValue()).isTrue(); - assertThat(option.isMultiValued()).isFalse(); - assertThat(option.isRequired()).isTrue(); - } - - @Test - public void testUsage() { - CLI command = CLIConfigurator.define(HelloClI.class); - StringBuilder builder = new StringBuilder(); - command.usage(builder); - assertThat(builder.toString()) - .containsIgnoringCase("Usage: hello -n ") - .containsIgnoringCase("A command saying hello.") - .containsIgnoringCase("A simple cli to wish you a good day. Pass your name with `--name`") - .containsIgnoringCase(" -n,--name your name"); - } - - @Name("test") - public static class CommandForDefaultValueTest { - @io.vertx.core.cli.annotations.Option(longName = "option", shortName = "o") - @DefaultValue("bar") - public void setFoo(String foo) { - } - } - - @Test - public void testOptionsWithDefaultValue() { - CLI cli = CLIConfigurator.define(CommandForDefaultValueTest.class); - - assertThat(cli.getOptions()).hasSize(1); - assertThat(find(cli.getOptions(), "option").getDefaultValue()).isEqualTo("bar"); - assertThat(find(cli.getOptions(), "option").getName()).isEqualTo("option"); - } - - @Name("test") - public static class CommandForDescriptionTest { - @io.vertx.core.cli.annotations.Option(longName = "option", shortName = "o") - @Description("This option is awesome") - public void setFoo(String foo) { - } - } - - @Test - public void testOptionsWithDescription() { - CLI cli = CLIConfigurator.define(CommandForDescriptionTest.class); - - assertThat(cli.getOptions()).hasSize(1); - assertThat(find(cli.getOptions(), "option").getDescription()) - .isEqualTo("This option is awesome"); - } - - @Name("test") - public static class CommandForParsedAsList { - @io.vertx.core.cli.annotations.Option(longName = "option", shortName = "o") - @ParsedAsList(separator = ":") - public void setFoo(List foo) { - - } - } - - @Test - public void testOptionsParsedAsList() { - CLI command = CLIConfigurator.define(CommandForParsedAsList.class); - assertThat(command.getOptions()).hasSize(1); - assertThat(((TypedOption) find(command.getOptions(), "option")) - .getListSeparator()).isEqualTo(":"); - assertThat(find(command.getOptions(), "option").isMultiValued()).isTrue(); - assertThat(((TypedOption) find(command.getOptions(), "option")).getType()) - .isEqualTo(String.class); - } - - @Name("test") - public static class CommandForTypeExtractTest { - @io.vertx.core.cli.annotations.Option(longName = "list", shortName = "l") - public void setFoo(List list) { - } - - @io.vertx.core.cli.annotations.Option(longName = "set", shortName = "s") - public void setFoo(Set set) { - } - - @io.vertx.core.cli.annotations.Option(longName = "collection", shortName = "c") - public void setFoo(Collection collection) { - } - - @io.vertx.core.cli.annotations.Option(longName = "tree", shortName = "t") - public void setFoo(TreeSet list) { - } - - @io.vertx.core.cli.annotations.Option(longName = "al", shortName = "al") - public void setFoo(ArrayList list) { - } - - @io.vertx.core.cli.annotations.Option(longName = "array", shortName = "a") - public void setFoo(int[] list) { - } - } - - @Test - public void testTypeExtraction() { - CLI command = CLIConfigurator.define(CommandForTypeExtractTest.class); - - assertThat(command.getOptions()).hasSize(6); - TypedOption model = (TypedOption) find(command.getOptions(), "list"); - assertThat(model.getType()).isEqualTo(String.class); - assertThat(model.isMultiValued()).isTrue(); - - model = (TypedOption) find(command.getOptions(), "set"); - assertThat(model.getType()).isEqualTo(Character.class); - assertThat(model.isMultiValued()).isTrue(); - - model = (TypedOption) find(command.getOptions(), "collection"); - assertThat(model.getType()).isEqualTo(Integer.class); - assertThat(model.isMultiValued()).isTrue(); - - model = (TypedOption) find(command.getOptions(), "tree"); - assertThat(model.getType()).isEqualTo(String.class); - assertThat(model.isMultiValued()).isTrue(); - - model = (TypedOption) find(command.getOptions(), "al"); - assertThat(model.getType()).isEqualTo(String.class); - assertThat(model.isMultiValued()).isTrue(); - - model = (TypedOption) find(command.getOptions(), "array"); - assertThat(model.getType()).isEqualTo(Integer.TYPE); - assertThat(model.isMultiValued()).isTrue(); - } - - @Test - public void testInjectionOfString() throws CLIException { - HelloClI command = new HelloClI(); - CLI cli = CLIConfigurator.define(HelloClI.class); - CommandLine evaluatedCLI = cli.parse(Arrays.asList("--name", "vert.x")); - CLIConfigurator.inject(evaluatedCLI, command); - - assertThat(command.run()).isEqualToIgnoringCase("Hello vert.x"); - assertThat(command.name).isEqualToIgnoringCase("vert.x"); - } - - private CommandLine parse(CLI cli, String... args) throws CLIException { - return cli.parse(Arrays.asList(args)); - } - - @Test - public void testSingleValueInjection() throws CLIException { - CLIWithSingleValue command = new CLIWithSingleValue(); - CLI cli = CLIConfigurator.define(command.getClass()); - CommandLine evaluatedCLI = parse(cli, "--boolean", "--short=1", "--byte=1", "--int=1", "--long=1", - "--double=1.1", "--float=1.1", "--char=c", "--string=hello"); - CLIConfigurator.inject(evaluatedCLI, command); - - assertThat(command.aBoolean).isTrue(); - assertThat(command.acceptValueBoolean).isTrue(); - assertThat(command.aShort).isEqualTo((short) 1); - assertThat(command.aByte).isEqualTo((byte) 1); - assertThat(command.anInt).isEqualTo(1); - assertThat(command.aLong).isEqualTo(1l); - assertThat(command.aDouble).isEqualTo(1.1d); - assertThat(command.aFloat).isEqualTo(1.1f); - assertThat(command.aChar).isEqualTo('c'); - assertThat(command.aString).isEqualTo("hello"); - - evaluatedCLI = parse(cli, "--boolean2", "--acceptValueBoolean=false", "--short2=1", "--byte2=1", "--int2=1", "--long2=1", - "--double2=1.1", "--float2=1.1", "--char2=c", "--string=hello"); - CLIConfigurator.inject(evaluatedCLI, command); - - assertThat(command.anotherBoolean).isTrue(); - assertThat(command.acceptValueBoolean).isFalse(); - assertThat(command.anotherShort).isEqualTo((short) 1); - assertThat(command.anotherByte).isEqualTo((byte) 1); - assertThat(command.anotherInt).isEqualTo(1); - assertThat(command.anotherLong).isEqualTo(1l); - assertThat(command.anotherDouble).isEqualTo(1.1d); - assertThat(command.anotherFloat).isEqualTo(1.1f); - assertThat(command.anotherChar).isEqualTo('c'); - assertThat(command.aString).isEqualTo("hello"); - - evaluatedCLI = parse(cli, "--acceptValueBoolean=xxx"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.acceptValueBoolean).isFalse(); - evaluatedCLI = parse(cli, "--acceptValueBoolean=true"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.acceptValueBoolean).isTrue(); - - evaluatedCLI = parse(cli, "--state=NEW"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.aState).isEqualTo(Thread.State.NEW); - - evaluatedCLI = parse(cli, "--person=vert.x"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.aPerson.name).isEqualTo("vert.x"); - - evaluatedCLI = parse(cli, "--person2=vert.x"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.anotherPerson.name).isEqualTo("vert.x"); - - evaluatedCLI = parse(cli, "--person3=vert.x"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.aThirdPerson.name).isEqualTo("vert.x"); - - evaluatedCLI = parse(cli, "--person4=bob,morane"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.aFourthPerson.first).isEqualTo("bob"); - assertThat(command.aFourthPerson.last).isEqualTo("morane"); - } - - @Test - public void testMultiValuesInjection() throws CLIException { - CLIWithMultipleValues command = new CLIWithMultipleValues(); - CLI cli = CLIConfigurator.define(command.getClass()); - - CommandLine evaluatedCLI = parse(cli, "--persons=x", "--persons", "y", "z"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.persons).hasSize(3); - - evaluatedCLI = parse(cli, "--persons2=x", "--persons2", "y", "z"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.persons2).hasSize(3); - - evaluatedCLI = parse(cli, "--persons3=x", "--persons3", "y", "z"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.persons3).hasSize(3); - - evaluatedCLI = parse(cli, "--persons4=x:y:z"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.persons4).hasSize(3); - - evaluatedCLI = parse(cli, "--states=NEW", "--states", "BLOCKED", "RUNNABLE"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.states).hasSize(3).containsExactly(Thread.State.NEW, Thread.State.BLOCKED, - Thread.State.RUNNABLE); - - evaluatedCLI = parse(cli, "--ints=1", "--ints", "2", "3"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.ints).hasSize(3).containsExactly(1, 2, 3); - - evaluatedCLI = parse(cli, "--shorts=1", "--shorts", "2", "3"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.shorts).hasSize(3).containsExactly((short) 1, (short) 2, (short) 3); - - evaluatedCLI = parse(cli, "--strings=a"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.strings).hasSize(1).containsExactly("a"); - - evaluatedCLI = parse(cli, "--doubles=1", "--doubles", "2.2", "3.3"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.doubles).hasSize(3).containsExactly(1.0, 2.2, 3.3); - } - - @Name("test") - public static class CommandForArgumentInjectionTest { - - AtomicReference reference = new AtomicReference<>(); - - @Argument(index = 0) - public void setX(String s) { - reference.set(s); - } - } - - @Test - public void testArgumentInjection() throws CLIException { - CommandForArgumentInjectionTest command = new CommandForArgumentInjectionTest(); - CLI cli = CLIConfigurator.define(command.getClass()).setName("test"); - CommandLine evaluatedCLI = parse(cli, "foo"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.reference.get()).isEqualTo("foo"); - } - - @Name("test") - public class CommandForConvertedValueTest { - AtomicReference reference = new AtomicReference<>(); - - @Argument(index = 0, required = false) - @DefaultValue("Bill,Balantine") - @ConvertedBy(Person4Converter.class) - public void setX(Person4 s) { - reference.set(s); - } - } - - @Test - public void testArgumentInjectionWithConvertedByAndDefaultValue() throws CLIException { - CommandForConvertedValueTest command = new CommandForConvertedValueTest(); - - CLI cli = CLIConfigurator.define(command.getClass()).setName("test"); - CommandLine evaluatedCLI = parse(cli, "Bob,Morane"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.reference.get().first).isEqualTo("Bob"); - assertThat(command.reference.get().last).isEqualTo("Morane"); - - evaluatedCLI = parse(cli); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.reference.get().first).isEqualTo("Bill"); - assertThat(command.reference.get().last).isEqualTo("Balantine"); - } - - @Name("test") - public static class CommandForMultipleArgumentTest { - - AtomicReference x = new AtomicReference<>(); - AtomicReference y = new AtomicReference<>(); - - @Argument(index = 0) - public void setX(String s) { - x.set(s); - } - - @Argument(index = 1) - public void setY(int s) { - y.set(s); - } - } - - @Test - public void testArgumentInjectionWithSeveralArguments() throws CLIException { - CommandForMultipleArgumentTest command = new CommandForMultipleArgumentTest(); - CLI cli = CLIConfigurator.define(command.getClass()).setName("test"); - CommandLine evaluatedCLI = parse(cli, "foo", "1"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.x.get()).isEqualTo("foo"); - assertThat(command.y.get()).isEqualTo(1); - } - - @Name("test") - public static class CommandWithDefaultValueOnArgument { - AtomicReference x = new AtomicReference<>(); - AtomicReference y = new AtomicReference<>(); - - @Argument(index = 0) - public void setX(String s) { - x.set(s); - } - - @Argument(index = 1, required = false) - @DefaultValue("25") - public void setY(int s) { - y.set(s); - } - } - - @Test - public void testArgumentWithDefaultValue() throws CLIException { - CommandWithDefaultValueOnArgument command = new CommandWithDefaultValueOnArgument(); - - CLI cli = CLIConfigurator.define(command.getClass()).setName("test"); - CommandLine evaluatedCLI = parse(cli, "foo"); - CLIConfigurator.inject(evaluatedCLI, command); - assertThat(command.x.get()).isEqualTo("foo"); - assertThat(command.y.get()).isEqualTo(25); - } - - private Option find(List