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/jettyjar
- ${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-analysisjar${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-analysisjarsources${source-assembly-directory}/lib/annotations
@@ -547,6 +547,14 @@
org.ow2.asmasm-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.corejackson-databind
- 2.8.1
+ 2.9.7org.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.transactionjavax.transaction-api
- 1.2compile
@@ -49,7 +48,6 @@
org.eclipse.jetty.orbitjavax.mail.glassfish
- 1.4.1.v201005082020test
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-utilorg/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.13.8.03.1.13.1.0
@@ -49,7 +50,6 @@
3.2.23.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
-
-
-