diff --git a/documentation/jetty/antora.yml b/documentation/jetty/antora.yml index ed38ab88e76c..360e7c29ed74 100644 --- a/documentation/jetty/antora.yml +++ b/documentation/jetty/antora.yml @@ -15,6 +15,7 @@ asciidoc: ee-prev: ee10 ee-prev-caps: EE 10 run-jetty-classpath: ${settings.localRepository}/org/eclipse/jetty/tests/jetty-testers/${project.version}/jetty-testers-${project.version}.jar${path.separator}${run.jetty.classpath} + servlet-current-version: 6.1.0 nav: - modules/operations-guide/nav.adoc - modules/programming-guide/nav.adoc diff --git a/documentation/jetty/modules/code/examples/pom.xml b/documentation/jetty/modules/code/examples/pom.xml index f40e0c86397c..ac864e2f1bbf 100644 --- a/documentation/jetty/modules/code/examples/pom.xml +++ b/documentation/jetty/modules/code/examples/pom.xml @@ -34,6 +34,10 @@ org.eclipse.jetty jetty-client + + org.eclipse.jetty + jetty-deploy + org.eclipse.jetty jetty-ethereum diff --git a/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java b/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java new file mode 100644 index 000000000000..4ba2bfc367a4 --- /dev/null +++ b/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java @@ -0,0 +1,217 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.docs.programming.server.deploy; + +import java.nio.file.Path; +import java.util.List; + +import org.eclipse.jetty.deploy.Deployer; +import org.eclipse.jetty.deploy.DeploymentScanner; +import org.eclipse.jetty.deploy.StandardDeployer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.server.handler.DefaultHandler; +import org.eclipse.jetty.util.component.Environment; +import org.eclipse.jetty.xml.EnvironmentBuilder; + +@SuppressWarnings("unused") +public class DeployDocs +{ + public void simple() throws Exception + { + // tag::simple[] + Server server = new Server(); + + // ContextHandlerCollection is required by the deployer. + ContextHandlerCollection contexts = new ContextHandlerCollection(); + server.setHandler(contexts); + + // Optional, shows the contexts deployed on the Server. + server.setDefaultHandler(new DefaultHandler()); + + // Create the deployer. + Deployer deployer = new StandardDeployer(contexts); + + // Create the DeploymentScanner to monitor the webapps directory. + DeploymentScanner scanner = new DeploymentScanner(server, deployer); + scanner.setWebappsDirectories(List.of(Path.of("/path/to/webapps"))); + // Link the lifecycle of the DeploymentScanner to the Server. + server.addBean(scanner); + + // Create an environment, with the name of your choice, + // and no extra class-path or module-path. + EnvironmentBuilder envBuilder = new EnvironmentBuilder("simple"); + Environment environment = envBuilder.build(); + + // Tell the DeploymentScanner about the environment + // it should use to deploy web applications. + scanner.configureEnvironment(environment.getName()); + + server.start(); + // end::simple[] + } + + public void jettyStatic() throws Exception + { + // tag::static[] + Server server = new Server(); + + // ContextHandlerCollection is required by the deployer. + ContextHandlerCollection contexts = new ContextHandlerCollection(); + server.setHandler(contexts); + + // Optional, shows the contexts deployed on the Server. + server.setDefaultHandler(new DefaultHandler()); + + // Create the deployer. + Deployer deployer = new StandardDeployer(contexts); + + // Create the DeploymentScanner to monitor the webapps directory. + DeploymentScanner scanner = new DeploymentScanner(server, deployer); + scanner.setWebappsDirectories(List.of(Path.of("/path/to/webapps"))); + // Link the lifecycle of the DeploymentScanner to the Server. + server.addBean(scanner); + + // Create the static environment. + EnvironmentBuilder envBuilder = new EnvironmentBuilder("static"); + envBuilder.addClassPath("/path/to/jetty-staticapp-{jetty-version}.jar"); // <1> + Environment environment = envBuilder.build(); + + // Tell the DeploymentScanner about the environment, and configure it for deployment. + DeploymentScanner.EnvironmentConfig envConfig = scanner.configureEnvironment(environment.getName()); // <2> + envConfig.setDefaultContextHandlerClassName("org.eclipse.jetty.staticapp.StaticAppContext"); + + server.start(); + // end::static[] + } + + public void jettyCore() throws Exception + { + // tag::core[] + Server server = new Server(); + + // ContextHandlerCollection is required by the deployer. + ContextHandlerCollection contexts = new ContextHandlerCollection(); + server.setHandler(contexts); + + // Optional, shows the contexts deployed on the Server. + server.setDefaultHandler(new DefaultHandler()); + + // Create the deployer. + Deployer deployer = new StandardDeployer(contexts); + + // Create the DeploymentScanner to monitor the webapps directory. + DeploymentScanner scanner = new DeploymentScanner(server, deployer); + scanner.setWebappsDirectories(List.of(Path.of("/path/to/webapps"))); + // Link the lifecycle of the DeploymentScanner to the Server. + server.addBean(scanner); + + // Create the core environment. + EnvironmentBuilder envBuilder = new EnvironmentBuilder("core"); + envBuilder.addClassPath("/path/to/jetty-coreapp-{jetty-version}.jar"); // <1> + Environment environment = envBuilder.build(); + + // Tell the DeploymentScanner about the environment, and configure it for deployment. + DeploymentScanner.EnvironmentConfig envConfig = scanner.configureEnvironment(environment.getName()); // <2> + envConfig.setDefaultContextHandlerClassName("org.eclipse.jetty.coreapp.CoreAppContext"); + + server.start(); + // end::core[] + } + + public void jakarta() throws Exception + { + // tag::jakarta[] + Server server = new Server(); + + // ContextHandlerCollection is required by the deployer. + ContextHandlerCollection contexts = new ContextHandlerCollection(); + server.setHandler(contexts); + + // Optional, shows the contexts deployed on the Server. + server.setDefaultHandler(new DefaultHandler()); + + // Create the deployer. + Deployer deployer = new StandardDeployer(contexts); + + // Create the DeploymentScanner to monitor the webapps directory. + DeploymentScanner scanner = new DeploymentScanner(server, deployer); + scanner.setWebappsDirectories(List.of(Path.of("/path/to/webapps"))); + // Link the lifecycle of the DeploymentScanner to the Server. + server.addBean(scanner); + + // Create the {ee-current} environment. + EnvironmentBuilder envBuilder = new EnvironmentBuilder("{ee-current}"); + envBuilder.addClassPath("/path/to/jakarta.servlet-api-{servlet-current-version}.jar"); // <1> + envBuilder.addClassPath("/path/to/jetty-{ee-current}-servlet-{jetty-version}.jar"); + envBuilder.addClassPath("/path/to/jetty-{ee-current}-webapp-{jetty-version}.jar"); + Environment environment = envBuilder.build(); + + // Tell the DeploymentScanner about the environment, and configure it for deployment. + DeploymentScanner.EnvironmentConfig envConfig = scanner.configureEnvironment(environment.getName()); + envConfig.setDefaultContextHandlerClassName("org.eclipse.jetty.{ee-current}.webapp.WebAppContext"); // <2> + envConfig.setDefaultsDescriptor("/path/to/{ee-current}-default-web.xml"); // <3> + // Other relevant Jakarta environment configurations. + + server.start(); + // end::jakarta[] + } + + public void multi() throws Exception + { + // tag::multi[] + Server server = new Server(); + + // ContextHandlerCollection is required by the deployer. + ContextHandlerCollection contexts = new ContextHandlerCollection(); + server.setHandler(contexts); + + // Optional, shows the contexts deployed on the Server. + server.setDefaultHandler(new DefaultHandler()); + + // Create the deployer. + Deployer deployer = new StandardDeployer(contexts); + + // Create the DeploymentScanner to monitor the webapps directory. + DeploymentScanner scanner = new DeploymentScanner(server, deployer); + scanner.setWebappsDirectories(List.of(Path.of("/path/to/webapps"))); + // Link the lifecycle of the DeploymentScanner to the Server. + server.addBean(scanner); + + // Create the core environment. + EnvironmentBuilder coreEnvBuilder = new EnvironmentBuilder("core"); + coreEnvBuilder.addClassPath("/path/to/jetty-coreapp-{jetty-version}.jar"); + Environment coreEnv = coreEnvBuilder.build(); + + // Create the {ee-current} environment. + EnvironmentBuilder jakartaEnvBuilder = new EnvironmentBuilder("{ee-current}"); + jakartaEnvBuilder.addClassPath("/path/to/jakarta.servlet-api-{servlet-current-version}.jar"); + jakartaEnvBuilder.addClassPath("/path/to/jetty-{ee-current}-servlet-{jetty-version}.jar"); + jakartaEnvBuilder.addClassPath("/path/to/jetty-{ee-current}-webapp-{jetty-version}.jar"); + Environment jakartaEnv = jakartaEnvBuilder.build(); + + // Tell the DeploymentScanner about the environments, and configure them for deployment. + + DeploymentScanner.EnvironmentConfig coreEnvConfig = scanner.configureEnvironment(coreEnv.getName()); + coreEnvConfig.setDefaultContextHandlerClassName("org.eclipse.jetty.coreapp.CoreAppContext"); + + DeploymentScanner.EnvironmentConfig jakartaEnvConfig = scanner.configureEnvironment(jakartaEnv.getName()); + jakartaEnvConfig.setDefaultContextHandlerClassName("org.eclipse.jetty.{ee-current}.webapp.WebAppContext"); + jakartaEnvConfig.setDefaultsDescriptor("/path/to/{ee-current}-default-web.xml"); + // Other relevant Jakarta environment configurations. + + server.start(); + // end::multi[] + } +} diff --git a/documentation/jetty/modules/programming-guide/nav.adoc b/documentation/jetty/modules/programming-guide/nav.adoc index b7372ea98078..d6085cb76114 100644 --- a/documentation/jetty/modules/programming-guide/nav.adoc +++ b/documentation/jetty/modules/programming-guide/nav.adoc @@ -24,6 +24,7 @@ ** xref:server/http3.adoc[] ** xref:server/compliance.adoc[] ** xref:server/session.adoc[] +** xref:server/deploy.adoc[] ** xref:server/websocket.adoc[] ** xref:server/fastcgi.adoc[] ** xref:server/io-arch.adoc[] diff --git a/documentation/jetty/modules/programming-guide/pages/server/deploy.adoc b/documentation/jetty/modules/programming-guide/pages/server/deploy.adoc new file mode 100644 index 000000000000..1ed7e1ffd83a --- /dev/null +++ b/documentation/jetty/modules/programming-guide/pages/server/deploy.adoc @@ -0,0 +1,210 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + += Web Application Deployment + +When using the xref:server/index.adoc[Jetty server libraries] in your code, web applications are typically assembled by composing the required ``Handler``s, as explained in xref:server/http.adoc#handler[this section]. + +When the `Server` instance is started, web applications are also started; there typically is no deployer component that can deploy web applications after the `Server` instance is started. + +The deployer component is the key component to deploy web applications when using Jetty as a standalone server, and it is detailed xref:operations-guide:deploy/index.adoc[here]. + +However, it is possible to use the Jetty server libraries in your code with the deployer component, so that you can deploy web applications after the `Server` instance is started. + +The Maven artifact coordinates are: + +[,xml,subs=attributes+] +---- + + org.eclipse.jetty + jetty-deploy + {jetty-version} + +---- + +The main components to set up are: + +* A `Deployer`, by default `org.eclipse.jetty.deploy.StandardDeployer`. +The deployer component is responsible for adding and removing a `ContextHandler` (or subclass) instance, that represents a web application, from the `Handler` tree, and is responsible for the lifecycle (starting and stopping) the `ContextHandler`. +* A `DeploymentScanner`, that scans directories for files or directories that represent web applications. +Typical web application files are `+*.war+`, `+*.properties+` and `+*.xml+` files. +When a web application file or directory is added/updated/removed, `DeploymentScanner` creates or retrieves (depending on the event) the corresponding `ContextHandler` and calls the `Deployer` to deploy/redeploy/undeploy the web application. + +[plantuml] +---- +skinparam backgroundColor transparent +skinparam monochrome true +skinparam shadowing false + +participant WebDir as "Web Application Directory" +participant DeploymentScanner +participant Deployer +participant ContextHandlerCollection + +DeploymentScanner -> WebDir : monitors for changes +-> WebDir : create webapp.war +DeploymentScanner -> Deployer : deploy ContextHandler +Deployer -> ContextHandlerCollection : deployHandler() + start +-> WebDir : delete webapp.war +DeploymentScanner -> Deployer : undeploy ContextHandler +Deployer -> ContextHandlerCollection : stop + removeHandler() +---- + +Each web application is deployed to a specific _environment_. + +The environment allows you to specify environmental properties that will be available to all web applications, as well as a `ClassLoader` that loads classes that are specific to the environment. + +Furthermore, the environment determines how the web application file should be interpreted: if it is a directory, whether it should be interpreted as a xref:operations-guide:deploy/index.adoc#web-application-format-static[Jetty Static web application], or as a xref:operations-guide:deploy/index.adoc#web-application-format-core[Jetty Core web application], or as a xref:operations-guide:deploy/index.adoc#web-application-format-jakarta[Jakarta EE exploded `+*.war+`]. + +By default, there are no environments; you must always create at least one, depending on the type of deployment you want for your web applications. + +[[simple]] +== Simple Deployer Setup + +The simplest deployer setup is when you deploy a web application via xref:operations-guide:deploy/index.adoc#context-xml[Jetty context XML file]: + +[,java,indent=0] +---- +include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java[tags=simple] +---- + +With this simple setup, you can only deploy Jetty context XML files. +In the Jetty context XML files, you can only reference classes that you have in the class-path or module-path, for example: + +.acme-webapp.xml +[,xml] +---- + + + /acme + + + + +---- +<1> This class must be in the class-path or module-path. + +WARNING: Do not be tempted to use this simple setup to deploy Jetty Core web applications, Jetty Static web applications, or Jakarta web applications; their setup is described their respective sections below. + +[[static]] +== Jetty Static Deployer Setup + +For xref:operations-guide:deploy/index.adoc#web-application-format-static[Jetty Static web applications], the setup is the following: + +[,java,indent=0,subs=+attributes] +---- +include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java[tags=static] +---- +<1> The environment is configured with its own class-path. +<2> Jetty Static web applications use `StaticAppContext` as their `ContextHandler`, so web application directories are interpreted as having the xref:operations-guide:deploy/index.adoc#web-application-format-static[Jetty Static web application format]. + +Your Jetty Static web application is a directory, for example `acme-asset/`, under `/path/to/webapps/`: + +[,bash] +---- +/path/to/webapps/ +└── acme-assets/ + ├── css/ + │ └── styles.css + └── index.html +---- + +[[core]] +== Jetty Core Deployer Setup + +For xref:operations-guide:deploy/index.adoc#web-application-format-core[Jetty Core web applications], the setup is the following: + +[,java,indent=0,subs=+attributes] +---- +include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java[tags=core] +---- +<1> The environment is configured with its own class-path. +<2> Jetty Core web applications use `CoreAppContext` as their `ContextHandler`, so web application directories are interpreted as having the xref:operations-guide:deploy/index.adoc#web-application-format-core[Jetty Core web application format]. + +Your Jetty Core web application is a directory, for example `acme-core-app/` under `/path/to/webapps/`: + +[,bash] +---- +/path/to/webapps/ +└── acme-core-app/ + ├── static # Static files are served from this directory. + │ └── favicon.ico + ├── classes # Where web application Java classes reside. + │ └── com + │ └── acme + │ └── AcmeHandler.class + ├── lib # Where web application Java libraries reside. + │ └── acme-util.jar + └── jetty-web.xml # Web application specific configuration. +---- + +With this setup you have the following class loader hierarchy, with the standard _parent first_ model for class loading: + +[,bash,subs=+attributes] +---- +System ClassLoader # jetty-server-{jetty-version}.jar, etc. +└── Environment ClassLoader # jetty-coreapp-{jetty-version}.jar + └── Jetty Core App ClassLoader # acme-core-app/classes/:acme-core-app/lib/acme-util.jar +---- + +[[jakarta]] +== Jakarta Deployer Setup + +For xref:operations-guide:deploy/index.adoc#web-application-format-jakarta[Jakarta web applications], the setup is the following: + +[,java,indent=0,subs=+attributes] +---- +include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java[tags=jakarta] +---- +<1> The environment is configured with its own class-path, that includes the Servlet API `+*.jar+` and the Jetty implementation `+*.jar+`s of the Servlet APIs. +<2> Jakarta web applications use `WebAppContext` as their `ContextHandler`, so web application `+*.war+` files or directories are interpreted as having the xref:operations-guide:deploy/index.adoc#web-application-format-jakarta[Jakarta web application format]. + +Your Jakarta web application is a `+*.war+` file, for example `acme.war` under `/path/to/webapps/`: + +[,bash] +---- +/path/to/webapps/ +└── acme.war +---- + +With this setup you have the following class loader hierarchy, with the standard Jakarta _web application first_ model for class loading: + +[,bash,subs=+attributes] +---- +System ClassLoader # jetty-server-{jetty-version}.jar: etc. +└── Environment ClassLoader # jakarta.servlet-api-{servlet-current-version}.jar: etc. + └── Jakarta Web App ClassLoader # acme.war!/WEB-INF/classes/:acme.war!/WEB-INF/lib/*.jar +---- + +[[multi]] +== Multiple Environments + +If you need to deploy web applications to different environments, for example `core` and `{ee-current}`, the setup is the following: + +[,java,indent=0,subs=+attributes] +---- +include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/deploy/DeployDocs.java[tags=multi] +---- + +The class loader hierarchy is the following: + +[,bash,subs=+attributes] +---- +System ClassLoader +├── core Environment ClassLoader +│ └── Jetty Core App ClassLoader +└── ee11 Environment ClassLoader + └── Jakarta Web App ClassLoader +---- + +With multiple environments, it is good practice to specify the web application `+*.properties+` file, as described in xref:operations-guide:deploy/index.adoc#web-application-files[this section].