diff --git a/Jenkinsfile b/Jenkinsfile index d116857064b..9ad5fa93007 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -22,58 +22,11 @@ def getFullBuild(jdk, os) { def settingsName = 'oss-settings.xml' def mavenOpts = '-Xms1g -Xmx4g -Djava.awt.headless=true' - try { - stage("Checkout - ${jdk}") { - checkout scm - } - } catch (Exception e) { - notifyBuild("Checkout Failure", jdk) - throw e - } - - try { - stage("Compile - ${jdk}") { - timeout(time: 15, unit: 'MINUTES') { - withMaven( - maven: mvnName, - jdk: "$jdk", - publisherStrategy: 'EXPLICIT', - globalMavenSettingsConfig: settingsName, - mavenOpts: mavenOpts, - mavenLocalRepo: localRepo) { - sh "mvn -V -B clean install -DskipTests -T6 -e" - } - } - } - } catch(Exception e) { - notifyBuild("Compile Failure", jdk) - throw e - } - - try { - stage("Javadoc - ${jdk}") { - timeout(time: 20, unit: 'MINUTES') { - withMaven( - maven: mvnName, - jdk: "$jdk", - publisherStrategy: 'EXPLICIT', - globalMavenSettingsConfig: settingsName, - mavenOpts: mavenOpts, - mavenLocalRepo: localRepo) { - sh "mvn -V -B javadoc:javadoc -T6 -e" - } - } - } - } catch(Exception e) { - notifyBuild("Javadoc Failure", jdk) - throw e - } - - try { - stage("Test - ${jdk}") { + stage("Build ${jdk}/${os}") { timeout(time: 90, unit: 'MINUTES') { // Run test phase / ignore test failures + checkout scm withMaven( maven: mvnName, jdk: "$jdk", @@ -83,6 +36,7 @@ def getFullBuild(jdk, os) { mavenOpts: mavenOpts, mavenLocalRepo: localRepo) { sh "mvn -V -B install -Dmaven.test.failure.ignore=true -e -Pmongodb -T3 -Djetty.testtracker.log=true -Dunix.socket.tmp="+env.JENKINS_HOME + sh "mvn -V -B javadoc:javadoc -T6 -e" } // withMaven doesn't label.. // Report failures in the jenkins UI @@ -112,6 +66,8 @@ def getFullBuild(jdk, os) { consoleParsers = [[parserName: 'Maven'], [parserName: 'JavaDoc'], [parserName: 'JavaC']]; + step([$class: 'MavenInvokerRecorder', reportsFilenamePattern: "**/target/invoker-reports/BUILD*.xml", + invokerBuildDir: "**/target/its"]) } // Report on Maven and Javadoc warnings diff --git a/VERSION.txt b/VERSION.txt index 95da0d1ed4a..4e4d526638d 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -99,6 +99,17 @@ jetty-9.3.25.v20180904 - 04 September 2018 + 2860 Leakage of HttpDestinations in HttpClient + 2871 Server reads -1 after client resets HTTP/2 stream +jetty-9.2.26.v20180806 - 06 August 2018 + + 2777 Workaround for Conscrypt's ssl == null + +jetty-9.2.25.v20180606 - 06 June 2018 + + 2114 Fix NPE in JettyHttpServerProvider + + 2135 Android 8.1 needs direct buffers for SSL/TLS to work + + 2529 HttpParser cleanup + + 2603 WebSocket ByteAccumulator initialized with wrong maximum + + 2604 WebSocket ByteAccumulator should report sizes in + MessageTooLargeException + jetty-9.4.11.v20180605 - 05 June 2018 + 1785 Support for vhost@connectorname syntax of virtual hosts + 2346 Revert stack trace logging for HTTPChannel.onException diff --git a/apache-jsp/pom.xml b/apache-jsp/pom.xml index 1110d177325..b82de9b0c08 100644 --- a/apache-jsp/pom.xml +++ b/apache-jsp/pom.xml @@ -10,7 +10,8 @@ http://www.eclipse.org/jetty jar - ${project.groupId}.${project.artifactId} + ${project.groupId}.apache-jsp + ${project.groupId}.apache.jsp diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_191.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_191.mod new file mode 100644 index 00000000000..ed8a55508d6 --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_191.mod @@ -0,0 +1,7 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[files] +maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_192.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_192.mod new file mode 100644 index 00000000000..ed8a55508d6 --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_192.mod @@ -0,0 +1,7 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[files] +maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar diff --git a/jetty-annotations/src/main/config/modules/annotations.mod b/jetty-annotations/src/main/config/modules/annotations.mod index ca8c3bad139..5c58290955c 100644 --- a/jetty-annotations/src/main/config/modules/annotations.mod +++ b/jetty-annotations/src/main/config/modules/annotations.mod @@ -13,3 +13,6 @@ lib/annotations/*.jar [xml] # Enable annotation scanning webapp configurations etc/jetty-annotations.xml + +[jpms] +add-modules:org.objectweb.asm diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java index 33e9f9e5f61..a23b6856167 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java @@ -35,6 +35,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.eclipse.jetty.util.JavaVersion; import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.ManifestUtils; import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiReleaseJarFile; import org.eclipse.jetty.util.log.Log; @@ -68,8 +69,8 @@ import org.objectweb.asm.Opcodes; public class AnnotationParser { private static final Logger LOG = Log.getLogger(AnnotationParser.class); - protected static int ASM_OPCODE_VERSION = Opcodes.ASM7; //compatibility of api - protected static String ASM_OPCODE_VERSION_STR = "ASM7"; + private static final int ASM_OPCODE_VERSION = Opcodes.ASM7; //compatibility of api + private static final String ASM_OPCODE_VERSION_STR = "ASM7"; /** * Map of classnames scanned and the first location from which scan occurred @@ -85,53 +86,49 @@ public class AnnotationParser public static int asmVersion () { int asmVersion = ASM_OPCODE_VERSION; - Package asm = Opcodes.class.getPackage(); - if (asm == null) - LOG.warn("Unknown asm runtime version, assuming version {}", ASM_OPCODE_VERSION_STR); + String version = ManifestUtils.getVersion(Opcodes.class).orElse(null); + if (version == null) + { + LOG.warn("Unknown ASM version, assuming {}", ASM_OPCODE_VERSION_STR); + } else { - String s = asm.getImplementationVersion(); - if (s==null) - LOG.info("Unknown asm implementation version, assuming version {}", ASM_OPCODE_VERSION_STR); - else + int dot = version.indexOf('.'); + version = version.substring(0, (dot < 0 ? version.length() : dot)).trim(); + try { - int dot = s.indexOf('.'); - s = s.substring(0, (dot < 0 ? s.length() : dot)).trim(); - try + int v = Integer.parseInt(version); + switch (v) { - int v = Integer.parseInt(s); - switch (v) + case 4: { - case 4: - { - asmVersion = Opcodes.ASM4; - break; - } - case 5: - { - asmVersion = Opcodes.ASM5; - break; - } - case 6: - { - asmVersion = Opcodes.ASM6; - break; - } - case 7: - { - asmVersion = Opcodes.ASM7; - break; - } - default: - { - LOG.warn("Unrecognized runtime asm version, assuming {}", ASM_OPCODE_VERSION_STR); - } + asmVersion = Opcodes.ASM4; + break; + } + case 5: + { + asmVersion = Opcodes.ASM5; + break; + } + case 6: + { + asmVersion = Opcodes.ASM6; + break; + } + case 7: + { + asmVersion = Opcodes.ASM7; + break; + } + default: + { + LOG.warn("Unrecognized ASM version, assuming {}", ASM_OPCODE_VERSION_STR); } } - catch (NumberFormatException e) - { - LOG.warn("Unable to parse runtime asm version, assuming version {}", ASM_OPCODE_VERSION_STR); - } + } + catch (NumberFormatException e) + { + LOG.warn("Unable to parse ASM version, assuming {}", ASM_OPCODE_VERSION_STR); } } return asmVersion; diff --git a/jetty-ant/pom.xml b/jetty-ant/pom.xml index fd54142b183..c4e070a4bc4 100644 --- a/jetty-ant/pom.xml +++ b/jetty-ant/pom.xml @@ -10,7 +10,7 @@ Jetty :: Ant Plugin - org.eclipse.jetty.ant + ${project.groupId}.ant diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponseException.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponseException.java index e494170c34e..b9e568d5821 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponseException.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponseException.java @@ -26,7 +26,12 @@ public class HttpResponseException extends RuntimeException public HttpResponseException(String message, Response response) { - super(message); + this(message, response, null); + } + + public HttpResponseException(String message, Response response, Throwable cause) + { + super(message, cause); this.response = response; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java index d2d620c5e9a..a3093b994b2 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java @@ -19,6 +19,8 @@ package org.eclipse.jetty.client; import java.nio.ByteBuffer; +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; @@ -338,18 +340,31 @@ public abstract class HttpSender implements AsyncContentProvider.Listener } } - protected boolean anyToFailure(Throwable failure) + private void anyToFailure(Throwable failure) { HttpExchange exchange = getHttpExchange(); if (exchange == null) - return false; + return; // Mark atomically the request as completed, with respect // to concurrency between request success and request failure. if (exchange.requestComplete(failure)) - return abort(exchange, failure); + executeAbort(exchange, failure); + } - return false; + private void executeAbort(HttpExchange exchange, Throwable failure) + { + try + { + Executor executor = getHttpChannel().getHttpDestination().getHttpClient().getExecutor(); + executor.execute(() -> abort(exchange, failure)); + } + catch (RejectedExecutionException x) + { + if (LOG.isDebugEnabled()) + LOG.debug(x); + abort(exchange, failure); + } } private void terminateRequest(HttpExchange exchange) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java index 2613e3a44b4..d6a9c2f96a5 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java @@ -346,7 +346,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res { HttpResponse response = exchange.getResponse(); response.status(failure.getCode()).reason(failure.getReason()); - failAndClose(new HttpResponseException("HTTP protocol violation: bad response on " + getHttpConnection(), response)); + failAndClose(new HttpResponseException("HTTP protocol violation: bad response on " + getHttpConnection(), response, failure)); } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java index 3c66cbfea36..ab9e274a29b 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java @@ -43,6 +43,7 @@ import org.eclipse.jetty.client.Origin; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.util.FutureResponseListener; import org.eclipse.jetty.http.HttpCompliance; +import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpVersion; @@ -209,6 +210,8 @@ public class HttpReceiverOverHTTPTest ExecutionException e = assertThrows(ExecutionException.class, ()->listener.get(5, TimeUnit.SECONDS)); assertThat(e.getCause(), instanceOf(HttpResponseException.class)); + assertThat(e.getCause().getCause(),instanceOf(BadMessageException.class)); + assertThat(e.getCause().getCause().getCause(),instanceOf(NumberFormatException.class)); } @ParameterizedTest diff --git a/jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc b/jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc index adb8a86e31a..648e18f59e9 100644 --- a/jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc @@ -347,6 +347,8 @@ The ALPN implementation, relying on modifications of OpenJDK classes, updates ev |1.8.0u171 |8.1.12.v20180117 |1.8.0u172 |8.1.12.v20180117 |1.8.0u181 |8.1.12.v20180117 +|1.8.0u191 |8.1.13.v20181017 +|1.8.0u192 |8.1.13.v20181017 |============================= [[alpn-build]] diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc index 441d8d47d87..3b63ab8ae5e 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc @@ -28,3 +28,4 @@ include::custom-modules.adoc[] include::startup-xml-config.adoc[] include::startup-unix-service.adoc[] include::startup-windows-service.adoc[] +include::startup-jpms.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/custom-modules.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/custom-modules.adoc index e070669d1be..dff59d79315 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/custom-modules.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/custom-modules.adoc @@ -79,6 +79,8 @@ If a user does not accept the license agreement, the module will not be activate Additional Startup Commands - `[exec]`:: The `[exec]` section is used to define additional parameters specific to the module. These commands are added to the server startup. +JPMS Module-Path Definitions - `[jpms]`:: +The `[jpms]` section is used to add link:#startup-jpms[JPMS modules] to the module-path for startup when using the `--jpms` command. [[custom-module-properties]] ==== Module Properties diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/startup-base-vs-home.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/startup-base-vs-home.adoc index e5c347a8a00..93634198870 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/startup-base-vs-home.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/startup-base-vs-home.adoc @@ -170,7 +170,7 @@ Note: order presented here is how they would appear on the classpath. 13: {VERSION} | ${jetty.home}/lib/jetty-jndi-{VERSION}.jar 14: 1.1.0.v201105071233 | ${jetty.home}/lib/jndi/javax.activation-1.1.0.v201105071233.jar 15: 1.4.1.v201005082020 | ${jetty.home}/lib/jndi/javax.mail.glassfish-1.4.1.v201005082020.jar -16: 1.2 | ${jetty.home}/lib/jndi/javax.transaction-api-1.2.jar +16: 1.3 | ${jetty.home}/lib/jndi/javax.transaction-api-1.3.jar 17: {VERSION} | ${jetty.home}/lib/jetty-rewrite-{VERSION}.jar 18: {VERSION} | ${jetty.home}/lib/jetty-security-{VERSION}.jar 19: {VERSION} | ${jetty.home}/lib/jetty-servlet-{VERSION}.jar diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/startup-classpath.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/startup-classpath.adoc index 4a51bc158bb..648664e42f6 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/startup-classpath.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/startup-classpath.adoc @@ -80,7 +80,7 @@ Note: order presented here is how they would appear on the classpath. 13: {VERSION} | ${jetty.home}/lib/jetty-jndi-{VERSION}.jar 14: 1.1.0.v201105071233 | ${jetty.home}/lib/jndi/javax.activation-1.1.0.v201105071233.jar 15: 1.4.1.v201005082020 | ${jetty.home}/lib/jndi/javax.mail.glassfish-1.4.1.v201005082020.jar -16: 1.2 | ${jetty.home}/lib/jndi/javax.transaction-api-1.2.jar +16: 1.3 | ${jetty.home}/lib/jndi/javax.transaction-api-1.3.jar 17: {VERSION} | ${jetty.home}/lib/jetty-rewrite-{VERSION}.jar 18: {VERSION} | ${jetty.home}/lib/jetty-security-{VERSION}.jar 19: {VERSION} | ${jetty.home}/lib/jetty-servlet-{VERSION}.jar diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/startup-jpms.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/startup-jpms.adoc new file mode 100644 index 00000000000..075b75d9c96 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/startup/startup-jpms.adoc @@ -0,0 +1,158 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ======================================================================== +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +[[startup-jpms]] +=== Startup using the Java Platform Module System (JPMS) + +Jetty modules also act ass automatic https://en.wikipedia.org/wiki/Java_Platform_Module_System[JPMS] modules via the `Automatic-Module-Name` attribute in the jar's `MANIFEST.MF` file. + +This makes possible to run Jetty from the module-path, rather than the class-path. + +We recommend using JDK 11 or greater due to the fact that JDK 11 removed all the "enterprise" modules from the JDK. +The classes in these "enterprise" modules were bundled with JDK 8, and present in "enterprise" modules in JDK 9 and JDK 10. +With JDK 11, these "enterprise" classes are either not available in the JDK (because their corresponding module was removed), or they are present in a different module. + +Because some of these "enterprise" classes are required by Jetty or by applications running in Jetty, it is better to use a stable source for those classes - in this case by using JDK 11 +or greater. + +[[jpms-module-path]] +==== Starting Jetty on the module-path + +To start Jetty on the module-path rather than the class-path, it is enough to add the `--jpms` option to the command line, for example: + +[source, screen, subs="{sub-order}"] +.... +$ mkdir my-jetty-base +$ cd my-jetty-base +$ java -jar $JETTY_HOME/start.jar --add-to-start=http +INFO : server transitively enabled, ini template available with --add-to-start=server +INFO : http initialized in ${jetty.base}/start.ini +INFO : threadpool transitively enabled, ini template available with --add-to-start=threadpool +INFO : Base directory was modified +$ java -jar $JETTY_HOME/start.jar --jpms +.... + +The example above creates a link:#startup-base-and-home[Jetty base directory] and enables the `http` module using the `--add-to-start` command. +The server then starts Jetty on the module-path using the `--jpms` option. + +---- +[NOTE] +When running on the module-path using the `--jpms` option, the Jetty start mechanism will fork a second JVM passing it the right JVM options to run on the module-path. + +You will have two JVMs running: one that runs `start.jar` and one that runs Jetty on the module-path. +---- + +If you are interested in the details of how the command line to run Jetty on the module-path looks like, you can add the `--dry-run` option: + +[source, screen, subs="{sub-order}"] +.... +$ java -jar $JETTY_HOME/start.jar --jpms --dry-run +.... + +This will give an out put looking something like this (broken in sections for clarity): + +[source, screen, subs="{sub-order}"] +.... +/opt/openjdk-11+28/bin/java +--module-path /opt/jetty/lib/servlet-api-3.1.jar:/opt/jetty/lib/jetty-schemas-3.1.jar:/opt/jetty/lib/jetty-http-9.4.13-SNAPSHOT.jar:... +--patch-module servlet.api=/opt/jetty/lib/jetty-schemas-3.1.jar +--module org.eclipse.jetty.xml/org.eclipse.jetty.xml.XmlConfiguration /opt/jetty/etc/jetty-threadpool.xml /opt/jetty/etc/jetty.xml ... +.... + +The `--module-path` option specifies the list of Jetty jars. +This list depends on the Jetty modules that have been enabled via the link:#startup-modules[`--add-to-start`] command. + +The `--patch-module` option is necessary for Servlet and JSP Containers to find XML DTDs and XML Schemas required to validate the various XML files present in web applications (such as `web.xml` and others). + +The `--module` option tells the JVM to run main class `XmlConfiguration` from the `org.eclipse.jetty.xml` module, with the given XML files as program arguments. + +When the JVM starts, module `org.eclipse.jetty.xml` is added to the set of JPMS _root modules_; all other Jetty modules, being automatic, will be resolved and added to the module graph. +JAR files that are not modules, such as `servlet-api-3.1.jar`, are on the module-path and therefore will be made automatic modules by the JVM (hence the derived module name `servlet.api` for this jar, referenced by the `--patch-module` command line option above). + +[[jpms-advanced-config]] +==== Advanced JPMS Configuration + +Web applications may need additional services from the Servlet Container, such as JDBC `DataSource` references or JTA `UserTransaction` references. + +For example, for JDBC it is typical to store, in JNDI, a reference to the connection pool's `DataSource` (such as `com.zaxxer.hikari.HikariDataSource`) or a reference directly to the JDBC driver's `DataSource` (`com.mysql.jdbc.jdbc2.optional.MysqlDataSource`). +Jetty needs to be able to instantiate those classes and therefore needs to be able to load those classes and all their super-classes, among which includes `javax.sql.DataSource`. + +When Jetty runs on the class-path, this is easily achieved by using a link:#custom-modules[custom module]: + +[source, screen, subs="{sub-order}"] +.mysql.mod +.... +[description] +MySQL module + +[lib] +lib/mysql/mysql-connector-java-*.jar +.... + +However, when running on the module-path, things are quite different. + +Class `javax.sql.DataSource` is in a JDK bundled module named `java.sql`, which is not automatic (it's a proper JPMS module) and it is not in the _root modules_ set. +Because it is not an automatic module, it is not added to the module graph, and therefore needs to be added explicitly using the JVM command line `--add-modules`. + +To add the JPMS module `java.sql` to the module graph, you need to modify your custom module in the following way, using our `mysql.mod` as an example: + +[source, screen, subs="{sub-order}"] +.mysql.mod +.... +[description] +MySQL module + +[lib] +lib/mysql/mysql-connector-java-*.jar + +[jpms] +add-modules: java.sql +.... + +The new `[jpms]` section is only used when Jetty is started on the module-path via the `--jpms` command line option. + +Assuming that `mysql-connector-java-*.jar` is a non JPMS modular jar, or an automatic JPMS modular jar, the Jetty start mechanism will add `mysql-connector-java-*.jar` to the module-path, and will add the JVM command line option `--add-modules java.sql`. + +If `mysql-connector-java-*.jar` were a proper JPMS modular jar with name (for example) `com.mysql.jdbc`, then it would need to be explicitly added to the module graph, in this way: + +[source, screen, subs="{sub-order}"] +.mysql.mod +.... +[description] +MySQL module + +[lib] +lib/mysql/mysql-connector-java-*.jar + +[jpms] +add-modules: com.mysql.jdbc +.... + +The JPMS module `java.sql` does not need to be explicitly added because it would be a dependency of the `com.mysql.jdbc` module and therefore automatically added to the module graph. + +The `[jpms]` section has the following format: + +[source, screen, subs="{sub-order}"] +.... +[jpms] +add-modules: (,)* +patch-module: =(:)* +add-opens: /=(,)* +add-exports: /=(,)* +add-reads: =(,)* +.... diff --git a/jetty-home/pom.xml b/jetty-home/pom.xml index c00b7b4bb6a..298d78ee5be 100644 --- a/jetty-home/pom.xml +++ b/jetty-home/pom.xml @@ -324,7 +324,7 @@ javax.annotation,org.eclipse.jetty.orbit,org.ow2.asm - javax.annotation-api,asm,asm-commons + javax.annotation-api,asm,asm-commons,asm-tree,asm-analysis jar ${assembly-directory}/lib/annotations @@ -337,7 +337,7 @@ javax.annotation,org.eclipse.jetty.orbit,org.ow2.asm - javax.annotation-api,asm,asm-commons + javax.annotation-api,asm,asm-commons,asm-tree,asm-analysis jar sources ${source-assembly-directory}/lib/annotations @@ -547,6 +547,14 @@ org.ow2.asm asm-commons + + org.ow2.asm + asm-tree + + + org.ow2.asm + asm-analysis + diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java index 6810a856aa7..0fa182ce2a7 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java @@ -52,9 +52,7 @@ public class BadMessageException extends RuntimeException public BadMessageException(int code, String reason) { - super(code+": "+reason); - _code=code; - _reason=reason; + this(code, reason, null); } public BadMessageException(int code, String reason, Throwable cause) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index 9284f75b81e..579b5ac90e5 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -1092,7 +1092,7 @@ public class HttpParser catch(NumberFormatException e) { LOG.ignore(e); - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Invalid Content-Length Value"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Invalid Content-Length Value",e); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 04279864c5d..fe2b90e6526 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -333,15 +333,16 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio } case SettingsFrame.ENABLE_PUSH: { + boolean enabled = value == 1; if (LOG.isDebugEnabled()) - LOG.debug("{} push for {}", pushEnabled ? "Enabling" : "Disabling", this); - pushEnabled = value == 1; + LOG.debug("{} push for {}", enabled ? "Enabling" : "Disabling", this); + pushEnabled = enabled; break; } case SettingsFrame.MAX_CONCURRENT_STREAMS: { if (LOG.isDebugEnabled()) - LOG.debug("Updating max local concurrent streams to {} for {}", maxLocalStreams, this); + LOG.debug("Updating max local concurrent streams to {} for {}", value, this); maxLocalStreams = value; break; } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index b9609ad4903..3cc9d531ce0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -176,7 +176,8 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa @Override public boolean isRemotelyClosed() { - return closeState.get() == CloseState.REMOTELY_CLOSED; + CloseState state = closeState.get(); + return state == CloseState.REMOTELY_CLOSED || state == CloseState.CLOSING; } public boolean isLocallyClosed() @@ -627,13 +628,14 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa @Override public String toString() { - return String.format("%s@%x#%d{sendWindow=%s,recvWindow=%s,reset=%b,%s,age=%d,attachment=%s}", + return String.format("%s@%x#%d{sendWindow=%s,recvWindow=%s,reset=%b/%b,%s,age=%d,attachment=%s}", getClass().getSimpleName(), hashCode(), getId(), sendWindow, recvWindow, - isReset(), + localReset, + remoteReset, closeState, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - timeStamp), attachment); diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index d891ab3dfe5..636d464686e 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -33,7 +33,7 @@ public class MetaDataBuilder { private final int _maxSize; private int _size; - private int _status=-1; + private Integer _status; private String _method; private HttpScheme _scheme; private HostPortHttpField _authority; @@ -47,7 +47,7 @@ public class MetaDataBuilder /** * @param maxHeadersSize The maximum size of the headers, expressed as total name and value characters. */ - MetaDataBuilder(int maxHeadersSize) + protected MetaDataBuilder(int maxHeadersSize) { _maxSize=maxHeadersSize; } @@ -84,7 +84,7 @@ public class MetaDataBuilder switch(header) { case C_STATUS: - if(checkHeader(header, _status)) + if(checkPseudoHeader(header, _status)) _status = (Integer)staticField.getStaticValue(); _response = true; break; @@ -110,8 +110,8 @@ public class MetaDataBuilder switch(header) { case C_STATUS: - if(checkHeader(header, _status)) - _status = field.getIntValue(); + if(checkPseudoHeader(header, _status)) + _status = Integer.valueOf(field.getIntValue()); _response = true; break; @@ -197,7 +197,7 @@ public class MetaDataBuilder } } - void streamException(String messageFormat, Object... args) + protected void streamException(String messageFormat, Object... args) { HpackException.StreamException stream = new HpackException.StreamException(messageFormat, args); if (_streamException==null) @@ -206,20 +206,7 @@ public class MetaDataBuilder _streamException.addSuppressed(stream); } - private boolean checkHeader(HttpHeader header, int value) - { - if (_fields.size()>0) - { - streamException("Pseudo header %s after fields", header.asString()); - return false; - } - if (value==-1) - return true; - streamException("Duplicate pseudo header %s", header.asString()); - return false; - } - - private boolean checkPseudoHeader(HttpHeader header, Object value) + protected boolean checkPseudoHeader(HttpHeader header, Object value) { if (_fields.size()>0) { @@ -258,22 +245,26 @@ public class MetaDataBuilder return new MetaData.Request(_method,_scheme,_authority,_path,HttpVersion.HTTP_2,fields,_contentLength); } if (_response) - return new MetaData.Response(HttpVersion.HTTP_2,_status,fields,_contentLength); + { + if (_status==null) + throw new HpackException.StreamException("No Status"); + return new MetaData.Response(HttpVersion.HTTP_2, _status, fields, _contentLength); + } return new MetaData(HttpVersion.HTTP_2,fields,_contentLength); } finally { - _fields = new HttpFields(Math.max(10,fields.size()+5)); - _request=false; - _response=false; - _status=-1; - _method=null; - _scheme=null; - _authority=null; - _path=null; - _size=0; - _contentLength=Long.MIN_VALUE; + _fields = new HttpFields(Math.max(10, fields.size() + 5)); + _request = false; + _response = false; + _status = null; + _method = null; + _scheme = null; + _authority = null; + _path = null; + _size = 0; + _contentLength = Long.MIN_VALUE; } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java index 801ce7bda87..d476885b1e0 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java @@ -451,12 +451,15 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable } catch (Throwable x) { - closeNoExceptions(_selector); _selector = null; if (isRunning()) LOG.warn(x); else + { + LOG.warn(x.toString()); LOG.debug(x); + } + closeNoExceptions(_selector); } return false; } diff --git a/jetty-maven-plugin/src/it/it-parent-pom/pom.xml b/jetty-maven-plugin/src/it/it-parent-pom/pom.xml index a58f3a3bc4c..2ad7f139b01 100644 --- a/jetty-maven-plugin/src/it/it-parent-pom/pom.xml +++ b/jetty-maven-plugin/src/it/it-parent-pom/pom.xml @@ -39,7 +39,7 @@ com.fasterxml.jackson.core jackson-databind - 2.8.1 + 2.9.7 org.slf4j diff --git a/jetty-plus/pom.xml b/jetty-plus/pom.xml index 5f5cdb99982..c9d45980978 100644 --- a/jetty-plus/pom.xml +++ b/jetty-plus/pom.xml @@ -43,7 +43,7 @@ true - javax.transaction*;version="[1.1,1.3)",* + javax.transaction.*;version="1.1",* diff --git a/jetty-quickstart/pom.xml b/jetty-quickstart/pom.xml index 1f76a98f0cb..4547244c9c4 100644 --- a/jetty-quickstart/pom.xml +++ b/jetty-quickstart/pom.xml @@ -37,7 +37,6 @@ javax.transaction javax.transaction-api - 1.2 compile @@ -49,7 +48,6 @@ org.eclipse.jetty.orbit javax.mail.glassfish - 1.4.1.v201005082020 test diff --git a/jetty-server/src/main/config/modules/server.mod b/jetty-server/src/main/config/modules/server.mod index f739beafbbb..2bd4718fd0d 100644 --- a/jetty-server/src/main/config/modules/server.mod +++ b/jetty-server/src/main/config/modules/server.mod @@ -24,6 +24,9 @@ lib/jetty-io-${jetty.version}.jar [xml] etc/jetty.xml +[jpms] +patch-module: servlet.api=lib/jetty-schemas-3.1.jar + [ini-template] ### Common HTTP configuration ## Scheme to use to build URIs for secure redirects diff --git a/jetty-start/pom.xml b/jetty-start/pom.xml index e5d7ce016b9..395490081a6 100644 --- a/jetty-start/pom.xml +++ b/jetty-start/pom.xml @@ -50,6 +50,7 @@ org.eclipse.jetty:jetty-util org/eclipse/jetty/util/JavaVersion* + org/eclipse/jetty/util/ManifestUtils* org/eclipse/jetty/util/TopologicalSort* diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java index 59c7dc72a46..c032034f2ed 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java @@ -18,11 +18,6 @@ package org.eclipse.jetty.start; -import static org.eclipse.jetty.start.UsageException.ERR_BAD_STOP_PROPS; -import static org.eclipse.jetty.start.UsageException.ERR_INVOKE_MAIN; -import static org.eclipse.jetty.start.UsageException.ERR_NOT_STOPPED; -import static org.eclipse.jetty.start.UsageException.ERR_UNKNOWN; - import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -44,6 +39,11 @@ import org.eclipse.jetty.start.Props.Prop; import org.eclipse.jetty.start.config.CommandLineConfigSource; import org.eclipse.jetty.start.config.ConfigSource; +import static org.eclipse.jetty.start.UsageException.ERR_BAD_STOP_PROPS; +import static org.eclipse.jetty.start.UsageException.ERR_INVOKE_MAIN; +import static org.eclipse.jetty.start.UsageException.ERR_NOT_STOPPED; +import static org.eclipse.jetty.start.UsageException.ERR_UNKNOWN; + /** * Main start class. *

@@ -353,9 +353,13 @@ public class Main // ------------------------------------------------------------ // 6) Resolve Extra XMLs args.resolveExtraXmls(); - + // ------------------------------------------------------------ - // 9) Resolve Property Files + // 7) JPMS Expansion + args.expandJPMS(activeModules); + + // ------------------------------------------------------------ + // 8) Resolve Property Files args.resolvePropertyFiles(); return args; diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java index 7bec2fe5b90..d449001d39c 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java @@ -59,7 +59,7 @@ import org.eclipse.jetty.start.Props.Prop; */ public class Module implements Comparable { - private static final String VERSION_UNSPECIFIED = "9.2"; + private static final String VERSION_UNSPECIFIED = "0.0"; static Pattern MOD_NAME = Pattern.compile("^(.*)\\.mod",Pattern.CASE_INSENSITIVE); static Pattern SET_PROPERTY = Pattern.compile("^(#?)\\s*([^=\\s]+)=(.*)$"); @@ -89,6 +89,9 @@ public class Module implements Comparable /** List of library options for this Module */ private final List _libs=new ArrayList<>(); + + /** List of JPMS options for this Module */ + private final List _jpms=new ArrayList<>(); /** List of files for this Module */ private final List _files=new ArrayList<>(); @@ -229,6 +232,11 @@ public class Module implements Comparable { return _xmls; } + + public List getJPMS() + { + return _jpms; + } public Version getVersion() { @@ -350,6 +358,9 @@ public class Module implements Comparable case "LIBS": _libs.add(line); break; + case "JPMS": + _jpms.add(line); + break; case "LICENSE": case "LICENSES": case "LICENCE": diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java index 69bcad311d9..e5930122ca4 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java @@ -154,6 +154,10 @@ public class Modules implements Iterable { System.out.printf(" XML: %s%n",xml); } + for (String jpms : module.getJPMS()) + { + System.out.printf(" JPMS: %s%n",jpms); + } for (String jvm : module.getJvmArgs()) { System.out.printf(" JVM: %s%n",jvm); diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java index 89eeebf0a79..58a31811064 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java @@ -27,21 +27,28 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; +import java.util.jar.Manifest; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import org.eclipse.jetty.start.Props.Prop; import org.eclipse.jetty.start.config.ConfigSource; import org.eclipse.jetty.start.config.ConfigSources; import org.eclipse.jetty.start.config.DirConfigSource; import org.eclipse.jetty.util.JavaVersion; +import org.eclipse.jetty.util.ManifestUtils; /** * The Arguments required to start Jetty. @@ -59,15 +66,11 @@ public class StartArgs // Use META-INF/MANIFEST.MF versions if (ver == null) { - Package pkg = StartArgs.class.getPackage(); - if ((pkg != null) && "Eclipse.org - Jetty".equals(pkg.getImplementationVendor()) && (pkg.getImplementationVersion() != null)) - { - ver = pkg.getImplementationVersion(); - if (tag == null) - { - tag = "jetty-" + ver; - } - } + ver = ManifestUtils.getManifest(StartArgs.class) + .map(Manifest::getMainAttributes) + .filter(attributes -> "Eclipse.org - Jetty".equals(attributes.getValue("Implementation-Vendor"))) + .map(attributes -> attributes.getValue("Implementation-Version")) + .orElse(null); } // Use jetty-version.properties values @@ -82,9 +85,9 @@ public class StartArgs props.load(in); ver = props.getProperty("jetty.version"); } - catch (IOException ignore) + catch (IOException x) { - StartLog.debug(ignore); + StartLog.debug(x); } } } @@ -94,23 +97,25 @@ public class StartArgs { ver = "0.0"; if (tag == null) - { tag = "master"; - } + } + else + { + if (tag == null) + tag = "jetty-" + ver; } // Set Tag Defaults - if (tag == null || tag.contains("-SNAPSHOT")) - { + if (tag.contains("-SNAPSHOT")) tag = "master"; - } VERSION = ver; - System.setProperty("jetty.version",VERSION); - System.setProperty("jetty.tag.version",tag); + System.setProperty("jetty.version", VERSION); + System.setProperty("jetty.tag.version", tag); } - private static final String SERVER_MAIN = "org.eclipse.jetty.xml.XmlConfiguration"; + private static final String MAIN_CLASS = "org.eclipse.jetty.xml.XmlConfiguration"; + private static final String MODULE_MAIN_CLASS = "org.eclipse.jetty.xml/org.eclipse.jetty.xml.XmlConfiguration"; private final BaseHome baseHome; @@ -132,6 +137,13 @@ public class StartArgs /** List of all active [xml] sections from enabled modules */ private List xmls = new ArrayList<>(); + /** List of all active [jpms] sections for enabled modules */ + private Set jmodAdds = new LinkedHashSet<>(); + private Map> jmodPatch = new LinkedHashMap<>(); + private Map> jmodOpens = new LinkedHashMap<>(); + private Map> jmodExports = new LinkedHashMap<>(); + private Map> jmodReads = new LinkedHashMap<>(); + /** JVM arguments, found via command line and in all active [exec] sections from enabled modules */ private List jvmArgs = new ArrayList<>(); @@ -174,6 +186,7 @@ public class StartArgs private boolean listConfig = false; private boolean version = false; private boolean dryRun = false; + private boolean jpms = false; private boolean createStartd = false; private boolean updateIni = false; private String mavenBaseUri; @@ -403,8 +416,7 @@ public class StartArgs return; } - List sortedKeys = new ArrayList<>(); - sortedKeys.addAll(systemPropertySource.keySet()); + List sortedKeys = new ArrayList<>(systemPropertySource.keySet()); Collections.sort(sortedKeys); for (String key : sortedKeys) @@ -446,11 +458,8 @@ public class StartArgs /** * Expand any command line added {@code --lib} lib references. - * - * @throws IOException - * if unable to expand the libraries */ - public void expandSystemProperties() throws IOException + public void expandSystemProperties() { StartLog.debug("Expanding System Properties"); @@ -467,7 +476,7 @@ public class StartArgs } /** - * Expand any command line added --lib lib references. + * Expand any command line added {@code --lib} lib references. * * @throws IOException * if unable to expand the libraries @@ -541,6 +550,70 @@ public class StartArgs } } + void expandJPMS(List activeModules) throws IOException + { + for (Module module : activeModules) + { + for (String line : module.getJPMS()) + { + line = properties.expand(line); + String directive; + if (line.startsWith(directive = "add-modules:")) + { + String[] names = line.substring(directive.length()).split(","); + Arrays.stream(names).map(String::trim).collect(Collectors.toCollection(() -> jmodAdds)); + } + else if (line.startsWith(directive = "patch-module:")) + { + parseJPMSKeyValue(module, line, directive, true, jmodPatch); + } + else if (line.startsWith(directive = "add-opens:")) + { + parseJPMSKeyValue(module, line, directive, false, jmodOpens); + } + else if (line.startsWith(directive = "add-exports:")) + { + parseJPMSKeyValue(module, line, directive, false, jmodExports); + } + else if (line.startsWith(directive = "add-reads:")) + { + parseJPMSKeyValue(module, line, directive, false, jmodReads); + } + else + { + throw new IllegalArgumentException("Invalid [jpms] directive " + directive + " in module " + module.getName() + ": " + line); + } + } + } + StartLog.debug("Expanded JPMS directives:%nadd-modules: %s%npatch-modules: %s%nadd-opens: %s%nadd-exports: %s%nadd-reads: %s", + jmodAdds, jmodPatch, jmodOpens, jmodExports, jmodReads); + } + + private void parseJPMSKeyValue(Module module, String line, String directive, boolean valueIsFile, Map> output) throws IOException + { + String valueString = line.substring(directive.length()); + int equals = valueString.indexOf('='); + if (equals <= 0) + throw new IllegalArgumentException("Invalid [jpms] directive " + directive + " in module " + module.getName() + ": " + line); + String delimiter = valueIsFile ? File.pathSeparator : ","; + String key = valueString.substring(0, equals).trim(); + String[] values = valueString.substring(equals + 1).split(delimiter); + Set result = output.computeIfAbsent(key, k -> new LinkedHashSet<>()); + for (String value : values) + { + value = value.trim(); + if (valueIsFile) + { + List paths = baseHome.getPaths(value); + paths.stream().map(Path::toAbsolutePath).map(Path::toString).collect(Collectors.toCollection(() -> result)); + } + else + { + result.add(value); + } + } + } + public List getStartModules() { return startModules; @@ -588,7 +661,7 @@ public class StartArgs cmd.addRawArg("-Djetty.home=" + baseHome.getHome()); cmd.addRawArg("-Djetty.base=" + baseHome.getBase()); - for (String x : jvmArgs) + for (String x : getJvmArgs()) { if (x.startsWith("-D")) { @@ -612,9 +685,64 @@ public class StartArgs cmd.addEqualsArg("-D" + propKey,value); } - cmd.addRawArg("-cp"); - cmd.addRawArg(classpath.toString()); - cmd.addRawArg(getMainClassname()); + if (isJPMS()) + { + Map> dirsAndFiles = StreamSupport.stream(classpath.spliterator(), false) + .collect(Collectors.groupingBy(File::isDirectory)); + List files = dirsAndFiles.get(false); + if (files != null && !files.isEmpty()) + { + cmd.addRawArg("--module-path"); + String modules = files.stream() + .map(File::getAbsolutePath) + .collect(Collectors.joining(File.pathSeparator)); + cmd.addRawArg(modules); + } + List dirs = dirsAndFiles.get(true); + if (dirs != null && !dirs.isEmpty()) + { + cmd.addRawArg("--class-path"); + String directories = dirs.stream() + .map(File::getAbsolutePath) + .collect(Collectors.joining(File.pathSeparator)); + cmd.addRawArg(directories); + } + + if (!jmodAdds.isEmpty()) + { + cmd.addRawArg("--add-modules"); + cmd.addRawArg(String.join(",", jmodAdds)); + } + for (Map.Entry> entry : jmodPatch.entrySet()) + { + cmd.addRawArg("--patch-module"); + cmd.addRawArg(entry.getKey() + "=" + String.join(File.pathSeparator, entry.getValue())); + } + for (Map.Entry> entry : jmodOpens.entrySet()) + { + cmd.addRawArg("--add-opens"); + cmd.addRawArg(entry.getKey() + "=" + String.join(",", entry.getValue())); + } + for (Map.Entry> entry : jmodExports.entrySet()) + { + cmd.addRawArg("--add-exports"); + cmd.addRawArg(entry.getKey() + "=" + String.join(",", entry.getValue())); + } + for (Map.Entry> entry : jmodReads.entrySet()) + { + cmd.addRawArg("--add-reads"); + cmd.addRawArg(entry.getKey() + "=" + String.join(",", entry.getValue())); + } + + cmd.addRawArg("--module"); + cmd.addRawArg(getMainClassname()); + } + else + { + cmd.addRawArg("-cp"); + cmd.addRawArg(classpath.toString()); + cmd.addRawArg(getMainClassname()); + } } @@ -657,8 +785,8 @@ public class StartArgs public String getMainClassname() { - String mainclass = System.getProperty("jetty.server",SERVER_MAIN); - return System.getProperty("main.class",mainclass); + String mainClass = System.getProperty("jetty.server", isJPMS() ? MODULE_MAIN_CLASS : MAIN_CLASS); + return System.getProperty("main.class", mainClass); } public String getMavenLocalRepoDir() @@ -765,6 +893,11 @@ public class StartArgs return createFiles; } + public boolean isJPMS() + { + return jpms; + } + public boolean isDryRun() { return dryRun; @@ -782,7 +915,7 @@ public class StartArgs public boolean isNormalMainClass() { - return SERVER_MAIN.equals(getMainClassname()); + return MAIN_CLASS.equals(getMainClassname()); } public boolean isHelp() @@ -974,6 +1107,14 @@ public class StartArgs return; } + if ("--jpms".equals(arg)) + { + jpms = true; + // Need to fork because we cannot use JDK 9 Module APIs. + exec = true; + return; + } + if ("--dry-run".equals(arg) || "--exec-print".equals(arg)) { dryRun = true; @@ -1084,10 +1225,7 @@ public class StartArgs if (arg.startsWith("--skip-file-validation=")) { List moduleNames = Props.getValues(arg); - for (String moduleName : moduleNames) - { - skipFileValidationModules.add(moduleName); - } + skipFileValidationModules.addAll(moduleNames); return; } @@ -1231,12 +1369,7 @@ public class StartArgs for (String moduleName : moduleNames) { modules.add(moduleName); - List list = sources.get(moduleName); - if (list == null) - { - list = new ArrayList<>(); - sources.put(moduleName,list); - } + List list = sources.computeIfAbsent(moduleName, k -> new ArrayList<>()); list.add(source); } } @@ -1327,17 +1460,7 @@ public class StartArgs @Override public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("StartArgs [enabledModules="); - builder.append(modules); - builder.append(", xmlRefs="); - builder.append(xmlRefs); - builder.append(", properties="); - builder.append(properties); - builder.append(", jvmArgs="); - builder.append(jvmArgs); - builder.append("]"); - return builder.toString(); + return String.format("%s[enabledModules=%s, xmlRefs=%s, properties=%s, jvmArgs=%s]", + getClass().getSimpleName(), modules, xmlRefs, properties, jvmArgs); } - } diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_191.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_191.mod new file mode 100644 index 00000000000..d8d1dbeebdf --- /dev/null +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_191.mod @@ -0,0 +1,5 @@ +[files] +maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_192.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_192.mod new file mode 100644 index 00000000000..d8d1dbeebdf --- /dev/null +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_192.mod @@ -0,0 +1,5 @@ +[files] +maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ManifestUtils.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ManifestUtils.java new file mode 100644 index 00000000000..83e9f5517a8 --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ManifestUtils.java @@ -0,0 +1,85 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util; + +import java.io.File; +import java.net.URL; +import java.security.CodeSource; +import java.util.Optional; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +public class ManifestUtils +{ + private ManifestUtils() + { + } + + public static Optional getManifest(Class klass) + { + try + { + CodeSource codeSource = klass.getProtectionDomain().getCodeSource(); + if (codeSource != null) + { + URL location = codeSource.getLocation(); + if (location != null) + { + try (JarFile jarFile = new JarFile(new File(location.toURI()))) + { + return Optional.of(jarFile.getManifest()); + } + } + } + return Optional.empty(); + } + catch (Throwable x) + { + return Optional.empty(); + } + } + + /** + *

Attempts to return the version of the jar/module for the given class.

+ *

First, retrieves the {@code Implementation-Version} main attribute of the manifest; + * if that is missing, retrieves the JPMS module version (via reflection); + * if that is missing, returns an empty Optional.

+ * + * @param klass the class of the jar/module to retrieve the version + * @return the jar/module version, or an empty Optional + */ + public static Optional getVersion(Class klass) + { + Optional version = getManifest(klass).map(Manifest::getMainAttributes) + .map(attributes -> attributes.getValue("Implementation-Version")); + if (version.isPresent()) + return version; + + try + { + Object module = klass.getClass().getMethod("getModule").invoke(klass); + Object descriptor = module.getClass().getMethod("getDescriptor").invoke(module); + return (Optional)descriptor.getClass().getMethod("rawVersion").invoke(descriptor); + } + catch (Throwable x) + { + return Optional.empty(); + } + } +} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java index 1280e6f29d5..a1847b3540a 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java @@ -39,8 +39,6 @@ import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Locale; -import java.util.Map; - import javax.servlet.MultipartConfigElement; import javax.servlet.ServletInputStream; import javax.servlet.http.Part; @@ -515,7 +513,7 @@ public class MultiPartInputStreamParser public Part getPart(String name) throws IOException { - if(_parsed) + if(!_parsed) parse(); throwIfError(); return _parts.getValue(name, 0); diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java index 862d3bd7605..2f86d7554e0 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java @@ -105,7 +105,7 @@ public abstract class Credential implements Serializable int l1 = known.length(); int l2 = unknown.length(); for (int i = 0; i < l2; ++i) - result &= known.charAt(i%l1) == unknown.charAt(i); + result &= ((l1==0)?unknown.charAt(l2-i-1):known.charAt(i%l1)) == unknown.charAt(i); return result && l1 == l2; } @@ -127,7 +127,7 @@ public abstract class Credential implements Serializable int l1 = known.length; int l2 = unknown.length; for (int i = 0; i < l2; ++i) - result &= known[i%l1] == unknown[i]; + result &= ((l1==0)?unknown[l2-i-1]:known[i%l1]) == unknown[i]; return result && l1 == l2; } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/security/CredentialTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/security/CredentialTest.java index a8aac3dbc48..5ea977f104a 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/security/CredentialTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/security/CredentialTest.java @@ -20,13 +20,13 @@ package org.eclipse.jetty.util.security; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import org.eclipse.jetty.util.security.Credential.Crypt; import org.eclipse.jetty.util.security.Credential.MD5; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * CredentialTest @@ -94,4 +94,20 @@ public class CredentialTest assertFalse(Credential.byteEquals("foo".getBytes(),"fo".getBytes())); assertFalse(Credential.byteEquals("foo".getBytes(),"bar".getBytes())); } + + @Test + public void testEmptyString() + { + assertFalse(Credential.stringEquals("fooo","")); + assertFalse(Credential.stringEquals("","fooo")); + assertTrue(Credential.stringEquals("","")); + } + + @Test + public void testEmptyBytes() + { + assertFalse(Credential.byteEquals("fooo".getBytes(),"".getBytes())); + assertFalse(Credential.byteEquals("".getBytes(),"fooo".getBytes())); + assertTrue(Credential.byteEquals("".getBytes(),"".getBytes())); + } } diff --git a/jetty-webapp/src/main/config/modules/webapp.mod b/jetty-webapp/src/main/config/modules/webapp.mod index 8b9186549bc..d41e57ce4a9 100644 --- a/jetty-webapp/src/main/config/modules/webapp.mod +++ b/jetty-webapp/src/main/config/modules/webapp.mod @@ -30,3 +30,6 @@ lib/jetty-webapp-${jetty.version}.jar ## #jetty.webapp.addSystemClasses+=,org.example. #jetty.webapp.addServerClasses+=,org.example. + +[jpms] +add-modules:java.instrument diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java index 8e7dc4b550f..f38bc347ad8 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java @@ -159,8 +159,6 @@ public class WebInfConfiguration extends AbstractConfiguration context.getMetaData().setWebInfClassesDirs(findClassDirs(context)); } - - /** * Find jars and directories that are on the container's classpath * and apply an optional filter. The filter is a pattern applied to the @@ -177,15 +175,15 @@ public class WebInfConfiguration extends AbstractConfiguration * @param context the WebAppContext being deployed * @throws Exception if unable to apply optional filtering on the container's classpath */ - public void findAndFilterContainerPaths (final WebAppContext context) - throws Exception + public void findAndFilterContainerPaths (final WebAppContext context) throws Exception { //assume the target jvm is the same as that running - int targetPlatform = JavaVersion.VERSION.getPlatform(); + int currentPlatform = JavaVersion.VERSION.getPlatform(); //allow user to specify target jvm different to current runtime + int targetPlatform = currentPlatform; Object target = context.getAttribute(JavaVersion.JAVA_TARGET_PLATFORM); if (target!=null) - targetPlatform = Integer.valueOf(target.toString()).intValue(); + targetPlatform = Integer.parseInt(target.toString()); //Apply an initial name filter to the jars to select which will be eventually //scanned for META-INF info and annotations. The filter is based on inclusion patterns. @@ -199,7 +197,7 @@ public class WebInfConfiguration extends AbstractConfiguration List containerUris = new ArrayList<>(); - while (loader != null && (loader instanceof URLClassLoader)) + while (loader instanceof URLClassLoader) { URL[] urls = ((URLClassLoader)loader).getURLs(); if (urls != null) @@ -219,12 +217,13 @@ public class WebInfConfiguration extends AbstractConfiguration loader = loader.getParent(); } - if (LOG.isDebugEnabled()) LOG.debug("Matching container urls {}", containerUris); + if (LOG.isDebugEnabled()) + LOG.debug("Matching container urls {}", containerUris); containerPathNameMatcher.match(containerUris); //if running on jvm 9 or above, we we won't be able to look at the application classloader //to extract urls, so we need to examine the classpath instead. - if (JavaVersion.VERSION.getPlatform() >= 9) + if (currentPlatform >= 9) { tmp = System.getProperty("java.class.path"); if (tmp != null) @@ -236,7 +235,8 @@ public class WebInfConfiguration extends AbstractConfiguration File f = new File(entry); cpUris.add(f.toURI()); } - if (LOG.isDebugEnabled()) LOG.debug("Matching java.class.path {}", cpUris); + if (LOG.isDebugEnabled()) + LOG.debug("Matching java.class.path {}", cpUris); containerPathNameMatcher.match(cpUris); } } @@ -253,28 +253,33 @@ public class WebInfConfiguration extends AbstractConfiguration { List moduleUris = new ArrayList<>(); String[] entries = tmp.split(File.pathSeparator); - for (String entry:entries) + for (String entry : entries) { - File dir = new File(entry); - File[] files = dir.listFiles(); - if (files != null) + File file = new File(entry); + if (file.isDirectory()) { - for (File f:files) + File[] files = file.listFiles(); + if (files != null) { - moduleUris.add(f.toURI()); + for (File f : files) + moduleUris.add(f.toURI()); } } - + else + { + moduleUris.add(file.toURI()); + } } - if (LOG.isDebugEnabled()) LOG.debug("Matching jdk.module.path {}", moduleUris); + if (LOG.isDebugEnabled()) + LOG.debug("Matching jdk.module.path {}", moduleUris); containerPathNameMatcher.match(moduleUris); } } - if (LOG.isDebugEnabled()) LOG.debug("Container paths selected:{}", context.getMetaData().getContainerResources()); + if (LOG.isDebugEnabled()) + LOG.debug("Container paths selected:{}", context.getMetaData().getContainerResources()); } - - + /** * Finds the jars that are either physically or virtually in * WEB-INF/lib, and applies an optional filter to their full diff --git a/jetty-webapp/src/test/resources/jetty-logging.properties b/jetty-webapp/src/test/resources/jetty-logging.properties index 4c4c7f8eddc..3c7f5b26a47 100644 --- a/jetty-webapp/src/test/resources/jetty-logging.properties +++ b/jetty-webapp/src/test/resources/jetty-logging.properties @@ -1,6 +1,5 @@ -# Setup default logging implementation for during testing org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -org.eclipse.jetty.LEVEL=INFO +#org.eclipse.jetty.LEVEL=DEBUG # org.eclipse.jetty.webapp.WebAppClassLoader.LEVEL=DEBUG # org.eclipse.jetty.util.LEVEL=DEBUG # org.eclipse.jetty.util.PathWatcher.Noisy.LEVEL=OFF diff --git a/pom.xml b/pom.xml index 9a16af6e4f2..cc1098231cf 100644 --- a/pom.xml +++ b/pom.xml @@ -39,9 +39,10 @@ false + ${bundle-symbolic-name} - 2.22.0 + 2.22.1 3.8.0 3.1.1 3.1.0 @@ -49,7 +50,6 @@ 3.2.2 3.5.2 - 5.1 @@ -488,6 +488,7 @@ ${project.build.outputDirectory}/META-INF/MANIFEST.MF + ${jpms-module-name} ${project.version} Eclipse.org - Jetty ${jetty.url} @@ -513,63 +514,6 @@ http://docs.oracle.com/javase/8/docs/api/ http://docs.oracle.com/javaee/7/api/ - - - org.apache.xbean.XBean - X - - - - phase - t - Phase: - - - goal - t - Goal: - - - description - a - Description: - - - parameter - f - Parameter: - - - required - f - Required: - - - readonly - f - Read-Only: - - - execute - X - - - - requiresDependencyResolution - X - - - - requiresProject - X - - - - threadSafe - X - - -
@@ -960,6 +904,16 @@ asm-commons ${asm.version} + + org.ow2.asm + asm-tree + ${asm.version} + + + org.ow2.asm + asm-analysis + ${asm.version} + org.eclipse.jetty.orbit javax.security.auth.message @@ -1002,7 +956,7 @@ javax.transaction javax.transaction-api - 1.2 + 1.3 provided @@ -1782,6 +1736,30 @@ 8.1.12.v20180117 + + 8u191 + + + java.version + 1.8.0_191 + + + + 8.1.13.v20181017 + + + + 8u192 + + + java.version + 1.8.0_192 + + + + 8.1.13.v20181017 + + jdk9 diff --git a/tests/test-quickstart/pom.xml b/tests/test-quickstart/pom.xml index 013d9ca080a..3e4363415b3 100644 --- a/tests/test-quickstart/pom.xml +++ b/tests/test-quickstart/pom.xml @@ -44,7 +44,6 @@ javax.transaction javax.transaction-api - 1.2 org.eclipse.jetty.tests @@ -139,7 +138,7 @@ copy - package + process-test-classes copy