//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

[[startup-jpms]]
=== Startup using the Java Platform Module System (JPMS)

Jetty modules also act as 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,
and therefore it guarantees a more stable platform to base your application's dependencies on.
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, and explicitly referencing the "enterprise" classes as dependencies, rather than assuming they are bundled with the JDK.

[[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 output 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/jetty-servlet-api-4.0.2.jar:/opt/jetty/lib/jetty-http-{VERSION}.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 `--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 `jetty-servlet-api-4.0.2.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: <module name>(,<module name>)*
patch-module: <module>=<file>(:<file>)*
add-opens: <module>/<package>=<target-module>(,<target-module>)*
add-exports: <module>/<package>=<target-module>(,<target-module>)*
add-reads: <module>=<target-module>(,<target-module>)*
....

[[jpms-module-path-alternative]]
==== Alternative way to start Jetty on the module-path

The section above uses the `--jpms` command line option to start Jetty on the module-path.
An alternative way of achieving the same result is to use a Jetty module, `$JETTY_BASE/modules/jpms.mod`,
that specifies that you want to run using JPMS (and possibly add some JPMS specific configuration).

[source, screen, subs="{sub-order}"]
.jpms.mod
....
[ini]
--jpms

[jpms]
# Additional JPMS configuration.
....

The `[ini]` section is equivalent to passing the `--jpms` option to the command line.
The `[jpms]` section (see also the link:#jpms-advanced-config[advanced JPMS configuration section])
allows you specify additional JPMS configuration.

[source, screen, subs="{sub-order}"]
....
$ mkdir jetty-base-jpms
$ cd jetty-base-jpms
$ mkdir modules
# Copy the jpms.mod file above into the $JETTY_BASE/modules/ directory.
$ cp /tmp/jpms.mod modules/
# Add both the http and the jpms modules.
$ java -jar $JETTY_HOME/start.jar --add-to-start=http,jpms
# Jetty will start on the module-path.
$ java -jar $JETTY_HOME/start.jar
....
