Fixes #5902 - Grab Jetty startup output in documentation. (#5906)

* Fixes #5902 - Grab Jetty startup output in documentation.

Implemented an Asciidoctor extension that uses `JettyHomeTester` to run
Jetty and capture its output.
This extension is triggered by the `ServiceLoader` mechanism, so the
documentation jar is now in the plugin classpath.

Introduced `jetty-halt.xml` so that the JVM can be halted.
In this way, Jetty does not produce the "stopping" log lines and
therefore they won't be grabbed and included in the documentation.

Used the new `include::jetty[]` directive in the documentation.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
Co-authored-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
Simone Bordet 2021-01-25 14:21:17 +01:00 committed by GitHub
parent d8e410bbff
commit 95b5cfd532
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 341 additions and 114 deletions

View File

@ -12,6 +12,15 @@
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-distribution</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-servlet-api</artifactId>
@ -82,16 +91,16 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.memcached</groupId>
<dependency>
<groupId>org.eclipse.jetty.memcached</groupId>
<artifactId>jetty-memcached-sessions</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-nosql</artifactId>
<version>${project.version}</version>
</dependency>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-nosql</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
@ -105,6 +114,11 @@
<artifactId>asciidoctorj-diagram</artifactId>
<version>2.0.5</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-documentation</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<configuration>
<backend>html5</backend>
@ -112,6 +126,8 @@
<require>asciidoctor-diagram</require>
</requires>
<attributes>
<MAVENREPOSITORY>${settings.localRepository}</MAVENREPOSITORY>
<PROJECTDIR>${project.basedir}/..</PROJECTDIR>
<JDURL>http://www.eclipse.org/jetty/javadoc/${project.version}</JDURL>
<JXURL>http://download.eclipse.org/jetty/stable-9/xref</JXURL>
<SRCDIR>${basedir}/..</SRCDIR>
@ -129,7 +145,7 @@
<executions>
<execution>
<id>index</id>
<phase>generate-resources</phase>
<phase>prepare-package</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
@ -141,7 +157,7 @@
</execution>
<execution>
<id>operations-guide</id>
<phase>generate-resources</phase>
<phase>prepare-package</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
@ -153,7 +169,7 @@
</execution>
<execution>
<id>contribution-guide</id>
<phase>generate-resources</phase>
<phase>prepare-package</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>

View File

@ -51,16 +51,13 @@ To deploy a standard web application, you need to enable the `deploy` module (se
----
$ java -jar $JETTY_HOME/start.jar --add-module=deploy
----
[source,options=nowrap]
----
INFO : webapp transitively enabled, ini template available with --add-module=webapp
INFO : security transitively enabled
INFO : servlet transitively enabled
INFO : deploy initialized in ${jetty.base}/start.d/deploy.ini
INFO : mkdir ${jetty.base}/webapps
INFO : Base directory was modified
include::jetty[setupArgs="--add-module=http",args="--add-module=deploy"]
----
The `deploy` module creates the `$JETTY_BASE/webapps` directory, the directory where `+*.war+` files or `+*.war+` directories should be copied so that Jetty can deploy them.
The `deploy` module creates the `$JETTY_BASE/webapps` directory, the directory where `+*.war+` files or web application directories should be copied so that Jetty can deploy them.
[NOTE]
====
@ -70,13 +67,11 @@ Whether these web applications are served via clear-text HTTP/1.1, or secure HTT
Refer to the xref:og-protocols[section about protocols] for further information.
====
Now you need to copy a web application to the `$JETTY_BASE/webapps` directory:
Now you need to copy a web application to the `$JETTY_BASE/webapps` directory, and you can use one of the demos shipped with Jetty:
----
curl https://repo1.maven.org/maven2/org/eclipse/jetty/test-jetty-webapp/10.0.0/test-jetty-webapp-10.0.0.war --output $JETTY_BASE/webapps/test.war
$ java -jar $JETTY_HOME/start.jar --add-module=demo-simple
----
// TODO: this webapp requires the login module, need something simpler.
// TODO: replace this with a module, so the download is done by the module.
The `$JETTY_BASE` directory is now:
@ -88,7 +83,7 @@ $JETTY_BASE
│ ├── deploy.ini
│ └── http.ini
└── webapps
└── test.war
└── demo-simple.war
----
Now start Jetty:
@ -96,20 +91,14 @@ Now start Jetty:
----
$ java -jar $JETTY_HOME/start.jar
----
----
2020-09-16 09:53:38.182:INFO :oejs.Server:main: jetty-10.0.0-SNAPSHOT; built: 2020-09-16T07:47:47.334Z; git: d45455b32d96f516d39e03b53e91502a34b04f37; jvm 15+36-1562
2020-09-16 09:53:38.205:INFO :oejdp.ScanningAppProvider:main: Deployment monitor [file:///tmp/jetty.base/webapps/] at interval 1
2020-09-16 09:53:38.293:WARN :oejshC.test:main: The async-rest webapp is deployed. DO NOT USE IN PRODUCTION!
2020-09-16 09:53:38.298:INFO :oejw.StandardDescriptorProcessor:main: NO JSP Support for /test, did not find org.eclipse.jetty.jsp.JettyJspServlet
2020-09-16 09:53:38.306:INFO :oejss.DefaultSessionIdManager:main: DefaultSessionIdManager workerName=node0
2020-09-16 09:53:38.306:INFO :oejss.DefaultSessionIdManager:main: No SessionScavenger set, using defaults
2020-09-16 09:53:38.307:INFO :oejss.HouseKeeper:main: node0 Scavenging every 660000ms
2020-09-16 09:53:38.331:INFO :oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@45b4c3a9{Async REST Webservice Example,/test,[file:///tmp/jetty-0_0_0_0-8080-test_war-_test-any-15202033063643714058.dir/webapp/, jar:file:///tmp/jetty-0_0_0_0-8080-test_war-_test-any-15202033063643714058.dir/webapp/WEB-INF/lib/example-async-rest-jar-10.0.0-SNAPSHOT.jar!/META-INF/resources],AVAILABLE}{/tmp/jetty.base/webapps/test.war}
2020-09-16 09:53:38.338:INFO :oejs.AbstractConnector:main: Started ServerConnector@543295b0{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
2020-09-16 09:53:38.347:INFO :oejs.Server:main: Started Server@5ffead27{STARTING}[10.0.0-SNAPSHOT,sto=5000] @593ms
----
// TODO: highlight the line that says that it deployed a context
Now you can access the web application by pointing your browser to `+http://localhost:8080/test+`.
[source,subs=quotes,options=nowrap]
----
include::jetty[setupArgs="--add-modules=http,deploy,demo-simple",highlight="WebAppContext"]
----
Note the highlighted line that logs the deployment of `demo-simple.war`.
Now you can access the web application by pointing your browser to `+http://localhost:8080/demo-simple+`.
If you want to customize the deployment of your web application, for example by specifying a `contextPath` different from the file/directory name, or by specifying JNDI entries, or by specifying virtual hosts, etc. read xref:og-deploy[this section].

View File

@ -29,11 +29,10 @@ $ JETTY_BASE=/path/to/jetty.base
$ cd $JETTY_BASE
$ java -jar $JETTY_HOME/start.jar
----
----
ERROR : Nothing to start, exiting ...
Usage: java -jar $JETTY_HOME/start.jar [options] [properties] [configs]
java -jar $JETTY_HOME/start.jar --help # for more information
[source,options=nowrap]
----
include::jetty[]
----
The error is normal, since the `$JETTY_BASE` you just created is empty and therefore there is no configuration to use to assemble the Jetty server.
@ -52,18 +51,10 @@ Try to enable the `http` module (see also xref:og-protocols-http[this section] f
----
$ java -jar $JETTY_HOME/start.jar --add-module=http
----
[source,options=nowrap]
----
INFO : mkdir ${jetty.base}/start.d
INFO : server transitively enabled, ini template available with --add-module=server
INFO : logging-jetty transitively enabled
INFO : http initialized in ${jetty.base}/start.d/http.ini
INFO : resources transitively enabled
INFO : threadpool transitively enabled, ini template available with --add-module=threadpool
INFO : logging/slf4j dynamic dependency of logging-jetty
INFO : bytebufferpool transitively enabled, ini template available with --add-module=bytebufferpool
INFO : mkdir ${jetty.base}/resources
INFO : copy ${jetty.home}/modules/logging/jetty/resources/jetty-logging.properties to ${jetty.base}/resources/jetty-logging.properties
INFO : Base directory was modified
include::jetty[args="--add-module=http"]
----
Now you can start Jetty:
@ -71,11 +62,10 @@ Now you can start Jetty:
----
$ java -jar $JETTY_HOME/start.jar
----
[source,subs=quotes]
[source,subs=quotes,options=nowrap]
----
2020-09-11 15:35:17.451:INFO :oejs.Server:main: jetty-10.0.0-SNAPSHOT; built: 2020-09-10T11:01:33.608Z; git: b10a14ebf9b200da388f4f9a2036bd8117ee0b11; jvm 11.0.8+10
2020-09-11 15:35:17.485:INFO :oejs.AbstractConnector:main: Started ServerConnector@2d52216b{HTTP/1.1, #(http/1.1)}{0.0.0.0:8080}#
2020-09-11 15:35:17.496:INFO :oejs.Server:main: Started Server@44821a96{STARTING}[10.0.0-SNAPSHOT,sto=5000] @553ms
include::jetty[args="--module=http",highlight="(\{.*:8080})"]
----
Note how Jetty is listening on port `8080` for clear-text HTTP/1.1 connections.
@ -128,11 +118,10 @@ If you restart Jetty, the new value will be used:
----
$ java -jar $JETTY_HOME/start.jar
----
[source,subs=quotes]
[source,subs=quotes,options=nowrap]
----
2020-09-11 15:35:17.451:INFO :oejs.Server:main: jetty-10.0.0-SNAPSHOT; built: 2020-09-10T11:01:33.608Z; git: b10a14ebf9b200da388f4f9a2036bd8117ee0b11; jvm 11.0.8+10
2020-09-11 15:35:17.485:INFO :oejs.AbstractConnector:main: Started ServerConnector@2d52216b{HTTP/1.1, #(http/1.1)}{0.0.0.0:9999}#
2020-09-11 15:35:17.496:INFO :oejs.Server:main: Started Server@44821a96{STARTING}[10.0.0-SNAPSHOT,sto=5000] @553ms
include::jetty[args="--module=http jetty.http.port=9999",highlight="(\{.*:9999})"]
----
Note how Jetty is now listening on port `9999` for clear-text HTTP/1.1 connections.

View File

@ -30,11 +30,10 @@ Starting Jetty yields:
----
$ java -jar $JETTY_HOME/start.jar
----
[source,subs=quotes]
[source,subs=quotes,options=nowrap]
----
2020-09-30 09:18:36.322:INFO :oejs.Server:main: jetty-10.0.0-SNAPSHOT; built: 2020-09-29T22:40:09.015Z; git: ba5f91fe00a68804a586b7dd4e2520c8c948dcc8; jvm 15+36-1562
2020-09-30 09:18:36.349:INFO :oejs.AbstractConnector:main: Started ServerConnector@636be97c##{HTTP/1.1, (http/1.1, h2c)}{0.0.0.0:8080}##
2020-09-30 09:18:36.361:INFO :oejs.Server:main: Started Server@3c72f59f{STARTING}[10.0.0-SNAPSHOT,sto=5000] @526ms
include::jetty[setupArgs="--add-modules=http,http2c",highlight="(\{.+:8080})"]
----
Note how Jetty is listening on port `8080` and the protocols supported are HTTP/1.1 and `h2c` (i.e. clear-text HTTP/2).

View File

@ -41,13 +41,10 @@ Starting Jetty yields:
----
$ java -jar $JETTY_HOME/start.jar
----
[source,subs=quotes]
[source,subs=quotes,options=nowrap]
----
2020-09-29 19:00:47.137:WARN :oejk.KeystoreGenerator:main: Generating Test Keystore: DO NOT USE IN PRODUCTION!
2020-09-29 19:00:47.316:INFO :oejs.Server:main: jetty-10.0.0-SNAPSHOT; built: 2020-09-29T13:28:40.441Z; git: 9c0082610528a846b366ae26f4c74894579a8e48; jvm 15+36-1562
2020-09-29 19:00:47.528:INFO :oejus.SslContextFactory:main: x509=X509@7770f470(mykey,h=[localhost],w=[]) for Server@24313fcc[provider=null,keyStore=file:///tmp/jetty.base/etc/test-keystore.p12,trustStore=file:///tmp/jetty.base/etc/test-keystore.p12]
2020-09-29 19:00:47.621:INFO :oejs.AbstractConnector:main: Started ServerConnector@73700b80##{SSL, (ssl, alpn, h2, http/1.1)}{0.0.0.0:8443}##
2020-09-29 19:00:47.630:INFO :oejs.Server:main: Started Server@30ee2816{STARTING}[10.0.0-SNAPSHOT,sto=5000] @746ms
include::jetty[setupArgs="--add-modules=ssl,http2,https,test-keystore",highlight="(\{.*:8443})"]
----
Note how Jetty is listening on port `8443` and the protocols supported are the sequence `(ssl, alpn, h2, http/1.1)`.

View File

@ -19,20 +19,10 @@ Secure HTTP/1.1 is enabled with both the `ssl` and `https` Jetty modules with th
----
$ java -jar $JETTY_HOME/start.jar --add-modules=ssl,https
----
[source,options=nowrap]
----
INFO : mkdir ${jetty.base}/start.d
INFO : server transitively enabled, ini template available with --add-module=server
INFO : logging-jetty transitively enabled
INFO : resources transitively enabled
INFO : https initialized in ${jetty.base}/start.d/https.ini
INFO : ssl initialized in ${jetty.base}/start.d/ssl.ini
INFO : threadpool transitively enabled, ini template available with --add-module=threadpool
INFO : logging/slf4j transitive provider of logging/slf4j for logging-jetty
INFO : logging/slf4j dynamic dependency of logging-jetty
INFO : bytebufferpool transitively enabled, ini template available with --add-module=bytebufferpool
INFO : mkdir ${jetty.base}/resources
INFO : copy ${jetty.home}/modules/logging/jetty/resources/jetty-logging.properties to ${jetty.base}/resources/jetty-logging.properties
INFO : Base directory was modified
include::jetty[args="--add-modules=ssl,https"]
----
The command above enables the `ssl` module, that provides the secure network connector, the KeyStore configuration and TLS configuration -- for more details see xref:og-protocols-ssl[this section].
@ -61,11 +51,10 @@ As a quick example, you can enable the xref:og-module-test-keystore[`test-keysto
----
$ java -jar $JETTY_HOME/start.jar --add-modules=test-keystore
----
[source,options=nowrap]
----
INFO : test-keystore initialized in ${jetty.base}/start.d/test-keystore.ini
INFO : mkdir ${jetty.base}/etc
INFO : copy ${jetty.home}/modules/test-keystore/test-keystore.p12 to ${jetty.base}/etc/test-keystore.p12
INFO : Base directory was modified
include::jetty[setupArgs="--add-modules=ssl,https",args="--add-modules=test-keystore"]
----
The `$JETTY_BASE` directory is now:
@ -87,12 +76,10 @@ Starting Jetty yields:
----
$ java -jar $JETTY_HOME/start.jar
----
[source,subs=quotes]
[source,subs=quotes,options=nowrap]
----
2020-09-22 08:40:49.482:INFO :oejs.Server:main: jetty-10.0.0-SNAPSHOT; built: 2020-09-21T14:44:05.094Z; git: 5c33f526e5b7426dd9644ece61b10184841bb8fa; jvm 15+36-1562
2020-09-22 08:40:49.709:INFO :oejus.SslContextFactory:main: x509=X509@14cd1699(mykey,h=[localhost],w=[]) for Server@73a1e9a9[provider=null,keyStore=file:///tmp/jetty.base/etc/test-keystore.p12,trustStore=file:///tmp/jetty.base/etc/test-keystore.p12]
2020-09-22 08:40:49.816:INFO :oejs.AbstractConnector:main: Started ServerConnector@2e1d27ba##{SSL, (ssl, http/1.1)}{0.0.0.0:8443}##
2020-09-22 08:40:49.828:INFO :oejs.Server:main: Started Server@2f177a4b{STARTING}[10.0.0-SNAPSHOT,sto=5000] @814ms
include::jetty[setupArgs="--add-modules=ssl,https,test-keystore",highlight="(\{.*:8443})"]
----
Note how Jetty is listening on port `8443` for the secure HTTP/1.1 protocol.

View File

@ -70,14 +70,21 @@ Forwarded: for=2.36.72.144:21216;proto=https
In the example above, the intermediary added the `Forwarded` header specifying that the client remote address is `2.36.72.144:21216` and that the request was made with the `https` scheme.
Support for the `Forwarded` HTTP header (and its predecessor `X-Forwarded-*` headers) is enabled with the `http-forwarded` Jetty module with the following command (issued from within the `$JETTY_BASE` directory):
Let's assume you have already configured Jetty with the HTTP/1.1 protocol with the following command (issued from within the `$JETTY_BASE` directory):
----
$ java -jar $JETTY_HOME/start.jar --add-module=http
----
Support for the `Forwarded` HTTP header (and its predecessor `X-Forwarded-*` headers) is enabled with the `http-forwarded` Jetty module:
----
$ java -jar $JETTY_HOME/start.jar --add-module=http-forwarded
----
[source,options=nowrap]
----
INFO : http-forwarded initialized in ${jetty.base}/start.d/http-forwarded.ini
INFO : Base directory was modified
include::jetty[setupArgs="--add-module=http",args="--add-module=http-forwarded"]
----
With the `http-forwarded` Jetty module enabled, Jetty interprets the `Forwarded` header and makes its information available to web applications via the standard Servlet APIs.
@ -103,14 +110,21 @@ Proxy protocol v2 has a binary format, carries the information about the client
Support for the proxy protocol can be enabled for the clear-text connector or for the secure connector (or both).
To enable proxy protocol support for the clear-text connector, enable the `proxy-protocol` Jetty module with the following command (issued from within the `$JETTY_BASE` directory):
Let's assume you have already configured Jetty with the HTTP/1.1 clear-text protocol with the following command (issued from within the `$JETTY_BASE` directory):
----
$ java -jar $JETTY_HOME/start.jar --add-module=http
----
To enable proxy protocol support for the clear-text connector, enable the `proxy-protocol` Jetty module:
----
$ java -jar $JETTY_HOME/start.jar --add-module=proxy-protocol
----
[source,options=nowrap]
----
INFO : proxy-protocol initialized in ${jetty.base}/start.d/proxy-protocol.ini
INFO : Base directory was modified
include::jetty[setupArgs="--add-module=http",args="--add-module=proxy-protocol"]
----
Starting Jetty yields:
@ -118,25 +132,32 @@ Starting Jetty yields:
----
$ java -jar $JETTY_HOME/start.jar
----
[source,subs=quotes]
[source,subs=quotes,options=nowrap]
----
2020-10-12 18:44:25.246:INFO :oejs.Server:main: jetty-10.0.0-SNAPSHOT; built: 2020-10-12T13:49:35.796Z; git: 1cd15e8d85feb308527c3df560734fc2ca1bc13c; jvm 15+36-1562
2020-10-12 18:44:25.267:INFO :oejdp.ScanningAppProvider:main: Deployment monitor [file:///tmp/jetty.base/webapps/]
2020-10-12 18:44:25.276:INFO :oejs.AbstractConnector:main: Started ServerConnector@7a8c8dcf{[proxy], ##([proxy], http/1.1)##}{0.0.0.0:8080}
2020-10-12 18:44:25.285:INFO :oejs.Server:main: Started Server@5c5eefef{STARTING}[10.0.0-SNAPSHOT,sto=5000] @486ms
include::jetty[args="--module=proxy-protocol",highlight="(\{.*:8080})"]
----
Note how in the example above the list of protocols for the clear-text connector is first `proxy` and then `http/1.1`.
For every new TCP connection, Jetty first interprets the proxy protocol bytes with the client information; after this initial proxy protocol processing, Jetty interprets the incoming bytes as HTTP/1.1 bytes.
Similarly, to enable proxy protocol support for the secure connector, enable the `proxy-protocol-ssl` Jetty module with the following command (issued from within the `$JETTY_BASE` directory):
Enabling proxy protocol support for the secure connector is similar.
Let's assume you have already configured Jetty with the HTTP/1.1 secure protocol and the test KeyStore with the following command (issued from within the `$JETTY_BASE` directory):
----
$ java -jar $JETTY_HOME/start.jar --add-module=https,test-keystore
----
Enable the `proxy-protocol-ssl` Jetty module with the following command (issued from within the `$JETTY_BASE` directory):
----
$ java -jar $JETTY_HOME/start.jar --add-module=proxy-protocol-ssl
----
[source,options=nowrap]
----
INFO : proxy-protocol-ssl initialized in ${jetty.base}/start.d/proxy-protocol-ssl.ini
INFO : Base directory was modified
include::jetty[setupArgs="--add-module=https",args="--add-module=proxy-protocol-ssl"]
----
Starting Jetty yields:
@ -144,13 +165,10 @@ Starting Jetty yields:
----
$ java -jar $JETTY_HOME/start.jar
----
[source,subs=quotes]
[source,subs=quotes,options=nowrap]
----
2020-10-12 19:09:38.397:INFO :oejs.Server:main: jetty-10.0.0-SNAPSHOT; built: 2020-10-12T13:49:35.796Z; git: 1cd15e8d85feb308527c3df560734fc2ca1bc13c; jvm 15+36-1562
2020-10-12 19:09:38.417:INFO :oejdp.ScanningAppProvider:main: Deployment monitor [file:///tmp/jetty.base/webapps/]
2020-10-12 19:09:38.605:INFO :oejus.SslContextFactory:main: x509=X509@4a7f959b(mykey,h=[localhost],w=[]) for Server@5403f35f[provider=null,keyStore=file:///tmp/jetty.base/etc/test-keystore.p12,trustStore=file:///tmp/jetty.base/etc/test-keystore.p12]
2020-10-12 19:09:38.697:INFO :oejs.AbstractConnector:main: Started ServerConnector@5afa3c9{[proxy], ##([proxy], ssl, http/1.1)##}{0.0.0.0:8443}
2020-10-12 19:09:38.705:INFO :oejs.Server:main: Started Server@54d9d12d{STARTING}[10.0.0-SNAPSHOT,sto=5000] @785ms
include::jetty[setupArgs="--add-modules=https,test-keystore,proxy-protocol-ssl",highlight="(\{.*:8443})"]
----
Note how in the example above the list of protocols for the secure connector is first `proxy`, then `ssl` and then `http/1.1`.
@ -175,7 +193,7 @@ HAProxy will need a single file containing the X509 certificates and the private
Refer to the xref:og-keystore[section about KeyStores] for more information about generating the required certificates and private key.
Now you can create the HAProxy configuration file (in Linux it's typically `/etc/haproxy/haproxy.cfg).
Now you can create the HAProxy configuration file (in Linux it's typically `/etc/haproxy/haproxy.cfg`).
This is a minimal configuration:
.haproxy.cfg

View File

@ -0,0 +1,169 @@
//
// ========================================================================
// Copyright (c) 1995-2021 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;
import java.nio.file.Path;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.ast.Document;
import org.asciidoctor.extension.IncludeProcessor;
import org.asciidoctor.extension.PreprocessorReader;
import org.asciidoctor.jruby.extension.spi.ExtensionRegistry;
import org.eclipse.jetty.tests.distribution.JettyHomeTester;
/**
* <p>Asciidoctor <em>include</em> extension that includes into
* the document the output produced by starting a Jetty server.</p>
* <p>Example usage in an Asciidoc page:</p>
* <pre>
* include::jetty[setupArgs="--add-modules=http,deploy,demo-simple",highlight="WebAppContext"]
* </pre>
* <p>Available configuration parameters are:</p>
* <dl>
* <dt>setupArgs</dt>
* <dd>Optional, specifies the arguments to use in a Jetty server <em>setup</em> run.
* If missing, no Jetty server <em>setup</em> run will be executed.
* The output produced by this run is ignored.</dd>
* <dt>args</dt>
* <dd>Optional, specifies the arguments to use in a Jetty server run.
* If missing, a Jetty server run will be executed with no arguments.
* The output produced by this run is included in the Asciidoc document.</dd>
* <dt>highlight</dt>
* <dd>Optional, specifies a regular expression that matches lines that should be highlighted.
* If missing, no line will be highlighted.
* If the regular expression contains capturing groups, only the text matching
* the groups is highlighted, not the whole line.
* </dd>
* </dl>
*
* @see JettyHomeTester
*/
public class JettyIncludeExtension implements ExtensionRegistry
{
public void register(Asciidoctor asciidoctor)
{
asciidoctor.javaExtensionRegistry().includeProcessor(JettyIncludeProcessor.class);
}
public static class JettyIncludeProcessor extends IncludeProcessor
{
@Override
public boolean handles(String target)
{
return "jetty".equals(target);
}
@Override
public void process(Document document, PreprocessorReader reader, String target, Map<String, Object> attributes)
{
try
{
Path projectPath = Path.of((String)document.getAttribute("projectdir"));
Path jettyHome = projectPath.resolve("jetty-home/target/jetty-home").normalize();
JettyHomeTester jetty = JettyHomeTester.Builder.newInstance()
.jettyHome(jettyHome)
.mavenLocalRepository((String)document.getAttribute("mavenrepository"))
.build();
String setupArgs = (String)attributes.get("setupArgs");
if (setupArgs != null)
{
try (JettyHomeTester.Run setupRun = jetty.start(setupArgs.split(" ")))
{
setupRun.awaitFor(15, TimeUnit.SECONDS);
}
}
String args = (String)attributes.get("args");
args = args == null ? "" : args + " ";
args += jettyHome.resolve("etc/jetty-halt.xml");
try (JettyHomeTester.Run run = jetty.start(args.split(" ")))
{
run.awaitFor(15, TimeUnit.SECONDS);
String output = captureOutput(attributes, jetty, run);
reader.push_include(output, "jettyHome_run", target, 1, attributes);
}
}
catch (Throwable x)
{
reader.push_include(x.toString(), "jettyHome_run", target, 1, attributes);
x.printStackTrace();
}
}
private String captureOutput(Map<String, Object> attributes, JettyHomeTester jetty, JettyHomeTester.Run run)
{
String highlight = (String)attributes.get("highlight");
return run.getLogs().stream()
.map(line -> redactPath(line, jetty.getJettyHome(), "/path/to/jetty.home"))
.map(line -> redactPath(line, jetty.getJettyBase(), "/path/to/jetty.base"))
.map(this::denoteLineStart)
.map(line -> highlight(line, highlight))
.collect(Collectors.joining(System.lineSeparator()));
}
private String redactPath(String line, Path path, String replacement)
{
return line.replaceAll(path.toString(), replacement);
}
private String denoteLineStart(String line)
{
// Matches lines that start with a date such as "2020-01-01 00:00:00.000:".
Pattern lineStart = Pattern.compile("(^[^:]+:[^:]+:[^:]+:)");
Matcher matcher = lineStart.matcher(line);
if (!matcher.find())
return line;
return "**" + matcher.group(1) + "**" + line.substring(matcher.end(1));
}
private String highlight(String line, String regExp)
{
if (regExp == null)
return line;
Matcher matcher = Pattern.compile(regExp).matcher(line);
if (!matcher.find())
return line;
int groupCount = matcher.groupCount();
// No capturing groups, highlight the whole line.
if (groupCount == 0)
return "##" + line + "##";
// Highlight the capturing groups.
StringBuilder result = new StringBuilder(line.length() + 4 * groupCount);
int start = 0;
for (int groupIndex = 1; groupIndex <= groupCount; ++groupIndex)
{
int matchBegin = matcher.start(groupIndex);
result.append(line, start, matchBegin);
result.append("##");
int matchEnd = matcher.end(groupIndex);
result.append(line, matchBegin, matchEnd);
result.append("##");
start = matchEnd;
}
result.append(line, start, line.length());
return result.toString();
}
}
}

View File

@ -0,0 +1 @@
org.eclipse.jetty.docs.JettyIncludeExtension

View File

@ -0,0 +1,10 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call name="addEventListener">
<Arg>
<New class="org.eclipse.jetty.util.component.HaltLifeCycleListener" />
</Arg>
</Call>
</Configure>

View File

@ -0,0 +1,27 @@
//
// ========================================================================
// Copyright (c) 1995-2021 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.util.component;
/**
* <p>A LifeCycle listener that halts the JVM with exit
* code {@code 0} when notified of the "started" event.</p>
*/
public class HaltLifeCycleListener implements LifeCycle.Listener
{
@Override
public void lifeCycleStarted(LifeCycle lifecycle)
{
Runtime.getRuntime().halt(0);
}
}

25
pom.xml
View File

@ -1213,6 +1213,31 @@
<artifactId>jboss-logging</artifactId>
<version>${jboss.logging.version}</version>
</dependency>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-constants</artifactId>
<version>0.10.0</version>
</dependency>
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-enxio</artifactId>
<version>0.32.1</version>
</dependency>
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-posix</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-unixsocket</artifactId>

View File

@ -154,7 +154,7 @@ public class JettyHomeTester
commands.add(config.jettyHome.toAbsolutePath() + "/start.jar");
// we get artifacts from local repo first
args = new ArrayList<>(args);
args.add("maven.local.repo=" + System.getProperty("mavenRepoPath"));
args.add("maven.local.repo=" + config.mavenLocalRepository);
commands.addAll(args);
LOGGER.info("Executing: {}", commands);