Merge remote-tracking branch 'origin/jetty-12.0.x' into jetty-12.1.x
This commit is contained in:
commit
151fffb48e
|
@ -101,4 +101,34 @@
|
|||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>eclipse-release</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>3.4.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce-java</id>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<requireJavaVersion>
|
||||
<version>[22,)</version>
|
||||
<message>[ERROR] OLD JDK [${java.version}] in use. Jetty Release ${project.version} MUST use JDK 22 or newer</message>
|
||||
</requireJavaVersion>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
|
|
@ -131,7 +131,7 @@ reportMavenTestFailures() {
|
|||
|
||||
echo ""
|
||||
if proceedyn "Are you sure you want to release using above? (y/N)" n; then
|
||||
mvn clean install -pl build -Dmaven.build.cache.enabled=false
|
||||
mvn clean install -pl build -Peclipse-release -Dmaven.build.cache.enabled=false
|
||||
echo ""
|
||||
if proceedyn "Update VERSION.txt for $VER_RELEASE? (Y/n)" y; then
|
||||
mvn -N -Pupdate-version generate-resources -Dmaven.build.cache.enabled=false
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
[[og-module-rewrite]]
|
||||
===== Module `rewrite`
|
||||
|
||||
The `rewrite` module inserts the `RewriteHandler` at the beginning of the `Handler` chain, providing URI-rewriting features similar to the link:https://httpd.apache.org/docs/current/mod/mod_rewrite.html[Apache's mod_rewrite] or the link:https://nginx.org/en/docs/http/ngx_http_rewrite_module.html[Nginx rewrite module].
|
||||
|
||||
The module properties are:
|
||||
|
||||
----
|
||||
include::{jetty-home}/modules/rewrite.mod[tags=documentation]
|
||||
----
|
||||
|
||||
A common use of the `rewrite` module is to redirect/rewrite old URI paths that have been renamed, for example from `+/old/*+` to `+/new/*+`; in this way, the old paths will not result in a `404` response, but rather be redirected/rewritten to the new paths.
|
||||
|
||||
`RewriteHandler` matches incoming requests against a set of rules that you can specify in the `$JETTY_BASE/etc/jetty-rewrite-rules.xml` file.
|
||||
|
||||
Rules can be matched against request data such as the request URI or the request headers; if there is a match, the rule is applied.
|
||||
|
||||
The rule file `$JETTY_BASE/etc/jetty-rewrite-rules.xml` is initially empty, but contains commented examples of rules that you can add.
|
||||
|
||||
The list of available rules can be found link:{javadoc-url}/org/eclipse/jetty/rewrite/handler/package-summary.html[here].
|
||||
|
||||
An example of `jetty-rewrite-rules.xml` is the following:
|
||||
|
||||
[source,xml]
|
||||
.jetty-rewrite-rules.xml
|
||||
----
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_10_0.dtd">
|
||||
<Configure id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RuleContainer">
|
||||
<Call name="addRule">
|
||||
<!-- Redirect with a 301 from /old/* to /new/* -->
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RedirectRegexRule">
|
||||
<Set name="statusCode">301</Set>
|
||||
<Set name="pattern">/old/(.*)</Set>
|
||||
<Set name="location">/new/$1</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
</Configure>
|
||||
----
|
||||
|
||||
Rules can be scoped to a specific virtual host.
|
||||
In the example below, the rule will only be evaluated if the virtual host matches `example.com`:
|
||||
|
||||
[source,xml]
|
||||
.jetty-rewrite-rules.xml
|
||||
----
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_10_0.dtd">
|
||||
<Configure id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RuleContainer">
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.VirtualHostRuleContainer">
|
||||
<Call name="addVirtualHost">
|
||||
<!-- Only match the example.com domain -->
|
||||
<Arg>example.com</Arg>
|
||||
</Call>
|
||||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule">
|
||||
<Set name="pattern">/advice</Set>
|
||||
<Set name="location">/support</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
</Configure>
|
||||
----
|
|
@ -30,6 +30,7 @@ include::module-jmx.adoc[]
|
|||
include::module-jmx-remote.adoc[]
|
||||
include::module-requestlog.adoc[]
|
||||
include::module-resources.adoc[]
|
||||
include::module-rewrite.adoc[]
|
||||
include::module-server.adoc[]
|
||||
include::module-ssl.adoc[]
|
||||
include::module-ssl-reload.adoc[]
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
[[pg-server-http-request-customizers]]
|
||||
==== Request Customizers
|
||||
|
||||
A request customizer is an instance of `HttpConfiguration.Customizer`, that can customize the HTTP request and/or the HTTP response headers _before_ the `Handler` chain is invoked.
|
||||
|
||||
Request customizers are added to a particular `HttpConfiguration` instance, and therefore are specific to a `Connector` instance: you can have two different ``Connector``s configured with different request customizers.
|
||||
|
||||
For example, it is common to configure a secure `Connector` with the `SecureRequestCustomizer` that customizes the HTTP request by adding attributes that expose TLS data associated with the secure communication.
|
||||
|
||||
A request customizer may:
|
||||
|
||||
* Inspect the received HTTP request method, URI, version and headers.
|
||||
* Wrap the `Request` object to allow any method to be overridden and customized. Typically this is done to synthesize additional HTTP request headers, or to change the return value of overridden methods.
|
||||
* Add or modify the HTTP response headers.
|
||||
|
||||
The out-of-the-box request customizers include:
|
||||
|
||||
* `ForwardedRequestCustomizer` -- to interpret the `Forwarded` (or the the obsolete ``+X-Forwarded-*+``) HTTP header added by a reverse proxy; see xref:pg-server-http-request-customizer-forwarded[this section].
|
||||
* `HostHeaderCustomizer` -- to customize, or synthesize it when original absent, the HTTP `Host` header; see xref:pg-server-http-request-customizer-host[this section].
|
||||
* `ProxyCustomizer` -- to expose as `Request` attributes the `ip:port` information carried by the PROXY protocol; see xref:pg-server-http-request-customizer-proxy[this section].
|
||||
* `RewriteCustomizer` -- to rewrite the request URI; see xref:pg-server-http-request-customizer-rewrite[this section].
|
||||
* `SecureRequestCustomizer` -- to expose TLS data via `Request` attributes; see xref:pg-server-http-request-customizer-secure[this section].
|
||||
|
||||
You can also write your own request customizers and add them to the `HttpConfiguration` instance along existing request customizers.
|
||||
Multiple request customizers will be invoked in the order they have been added.
|
||||
|
||||
Below you can find an example of how to add a request customizer:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java[tags=requestCustomizer]
|
||||
----
|
||||
|
||||
[[pg-server-http-request-customizer-forwarded]]
|
||||
===== `ForwardedRequestCustomizer`
|
||||
|
||||
`ForwardedRequestCustomizer` should be added when Jetty receives requests from a reverse proxy on behalf of a remote client, and web applications need to access the remote client information.
|
||||
|
||||
The reverse proxy adds the `Forwarded` (or the obsolete ``+X-Forwarded-*+``) HTTP header to the request, and may offload TLS so that the request arrives in clear-text to Jetty.
|
||||
|
||||
Applications deployed in Jetty may need to access information related to the remote client, for example the remote IP address and port, or whether the request was sent through a secure communication channel.
|
||||
However, the request is forwarded by the reverse proxy, so the direct information about the remote IP address is that of the proxy, not of the remote client.
|
||||
Furthermore, the proxy may offload TLS and forward the request in clear-text, so that the URI scheme would be `http` as forwarded by the reverse proxy, not `https` as sent by the remote client.
|
||||
|
||||
`ForwardedRequestCustomizer` reads the `Forwarded` header where the reverse proxy saved the remote client information, and wraps the original `Request` so that applications will transparently see the remote client information when calling methods such as `Request.isSecure()`, or `Request.getConnectionMetaData().getRemoteSocketAddress()`, etc.
|
||||
|
||||
For more information about how to configure `ForwardedRequestCustomizer`, see also link:{javadoc-url}/org/eclipse/jetty/server/ForwardedRequestCustomizer.html[the javadocs].
|
||||
|
||||
[[pg-server-http-request-customizer-host]]
|
||||
===== `HostHeaderCustomizer`
|
||||
|
||||
`HostHeaderCustomizer` should be added when Jetty receives requests that may lack the `Host` HTTP header, such as HTTP/1.0, HTTP/2 or HTTP/3 requests, and web applications have logic that depends on the value of the `Host` HTTP header.
|
||||
|
||||
For HTTP/2 and HTTP/3, the `Host` HTTP header is missing because the authority information is carried by the `:authority` pseudo-header, as per the respective specifications.
|
||||
|
||||
`HostHeaderCustomizer` will look at the `:authority` pseudo-header, then wrap the original `Request` adding a `Host` HTTP header synthesized from the `:authority` pseudo-header.
|
||||
In this way, web applications that rely on the presence of the `Host` HTTP header will work seamlessly in any HTTP protocol version.
|
||||
|
||||
`HostHeaderCustomizer` works also for the WebSocket protocol.
|
||||
|
||||
WebSocket over HTTP/2 or over HTTP/3 initiate the WebSocket communication with an HTTP request that only has the `:authority` pseudo-header.
|
||||
`HostHeaderCustomizer` synthesizes the `Host` HTTP header for such requests, so that WebSocket web applications that inspect the initial HTTP request before the WebSocket communication will work seamlessly in any HTTP protocol version.
|
||||
|
||||
For more information about how to configure `HostHeaderCustomizer`, see also link:{javadoc-url}/org/eclipse/jetty/server/HostHeaderCustomizer.html[the javadocs].
|
||||
|
||||
[[pg-server-http-request-customizer-proxy]]
|
||||
===== `ProxyCustomizer`
|
||||
|
||||
`ProxyCustomizer` should be added when Jetty receives requests from a reverse proxy on behalf of a remote client, prefixed by the PROXY protocol (see also this section about the xref:pg-server-http-connector-protocol-proxy-http11[PROXY protocol]).
|
||||
|
||||
`ProxyCustomizer` adds the reverse proxy IP address and port as `Request` attributes.
|
||||
Web applications may use these attributes in conjunction with the data exposed by `ForwardedRequestCustomizer` (see xref:pg-server-http-request-customizer-forwarded[this section]).
|
||||
|
||||
For more information about how to configure `ProxyCustomizer`, see also link:{javadoc-url}/org/eclipse/jetty/server/ProxyCustomizer.html[the javadocs].
|
||||
|
||||
[[pg-server-http-request-customizer-rewrite]]
|
||||
===== `RewriteCustomizer`
|
||||
|
||||
`RewriteCustomizer` is similar to `RewriteHandler` (see xref:pg-server-http-handler-use-rewrite[this section]), but a `RewriteCustomizer` cannot send a response or otherwise complete the request/response processing.
|
||||
|
||||
A `RewriteCustomizer` is mostly useful if you want to rewrite the request URI _before_ the `Handler` chain is invoked.
|
||||
However, a very similar effect can be achieved by having the `RewriteHandler` as the first `Handler` (the child `Handler` of the `Server` instance).
|
||||
|
||||
Since `RewriteCustomizer` cannot send a response or complete the request/response processing, ``Rule``s that do so such as redirect rules have no effect and are ignored; only ``Rule``s that modify or wrap the `Request` will have effect and be applied.
|
||||
|
||||
Due to this limitation, it is often a better choice to use `RewriteHandler` instead of `RewriteCustomizer`.
|
||||
|
||||
For more information about how to configure `RewriteCustomizer`, see also link:{javadoc-url}/org/eclipse/jetty/rewrite/RewriteCustomizer.html[the javadocs].
|
||||
|
||||
[[pg-server-http-request-customizer-secure]]
|
||||
===== `SecureRequestCustomizer`
|
||||
|
||||
`SecureRequestCustomizer` should be added when Jetty receives requests over a secure `Connector`.
|
||||
|
||||
`SecureRequestCustomizer` adds TLS information as request attributes, in particular an instance of `EndPoint.SslSessionData` that contains information about the negotiated TLS cipher suite and possibly client certificates, and an instance of `org.eclipse.jetty.util.ssl.X509` that contains information about the server certificate.
|
||||
|
||||
`SecureRequestCustomizer` also adds, if configured so, the `Strict-Transport-Security` HTTP response header (for more information about this header, see link:https://datatracker.ietf.org/doc/html/rfc6797[its specification]).
|
||||
|
||||
For more information about how to configure `SecureRequestCustomizer`, see also link:{javadoc-url}/org/eclipse/jetty/server/SecureRequestCustomizer.html[the javadocs].
|
|
@ -0,0 +1,48 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
[[pg-server-http-request-logging]]
|
||||
==== Request Logging
|
||||
|
||||
HTTP requests and responses can be logged to provide data that can be later analyzed with other tools.
|
||||
These tools can provide information such as the most frequently accessed request URIs, the response status codes, the request/response content lengths, geographical information about the clients, etc.
|
||||
|
||||
The default request/response log line format is the link:https://en.wikipedia.org/wiki/Common_Log_Format[NCSA Format] extended with referrer data and user-agent data.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Typically, the extended NCSA format is the is enough and it's the standard used and understood by most log parsing tools and monitoring tools.
|
||||
|
||||
To customize the request/response log line format see the link:{javadoc-url}/org/eclipse/jetty/server/CustomRequestLog.html[`CustomRequestLog` javadocs].
|
||||
====
|
||||
|
||||
Request logging can be enabled at the `Server` level.
|
||||
|
||||
The request logging output can be directed to an SLF4J logger named `"org.eclipse.jetty.server.RequestLog"` at `INFO` level, and therefore to any logging library implementation of your choice (see also xref:pg-troubleshooting-logging[this section] about logging).
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java[tags=serverRequestLogSLF4J]
|
||||
----
|
||||
|
||||
Alternatively, the request logging output can be directed to a daily rolling file of your choice, and the file name must contain `yyyy_MM_dd` so that rolled over files retain their date:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java[tags=serverRequestLogFile]
|
||||
----
|
||||
|
||||
For maximum flexibility, you can log to multiple ``RequestLog``s using class `RequestLog.Collection`, for example by logging with different formats or to different outputs.
|
||||
|
||||
You can use `CustomRequestLog` with a custom `RequestLog.Writer` to direct the request logging output to your custom targets (for example, an RDBMS).
|
||||
You can implement your own `RequestLog` if you want to have functionalities that are not implemented by `CustomRequestLog`.
|
|
@ -123,9 +123,13 @@ First, the Jetty I/O layer emits an event that a socket has data to read.
|
|||
This event is converted to a call to `AbstractConnection.onFillable()`, where the `Connection` first reads from the `EndPoint` into a `ByteBuffer`, and then calls a protocol specific parser to parse the bytes in the `ByteBuffer`.
|
||||
|
||||
The parser emit events that are protocol specific; the HTTP/2 parser, for example, emits events for each HTTP/2 frame that has been parsed, and similarly does the HTTP/3 parser.
|
||||
The parser events are then converted to protocol independent events such as _"request start"_, _"request headers"_, _"request content chunk"_, etc.
|
||||
The parser events are then converted to protocol independent events such as _"request start"_, _"request headers"_, _"request content chunk"_, etc. detailed in xref:pg-server-http-request-processing-events[this section].
|
||||
|
||||
When enough of the HTTP request is arrived, the `Connection` calls `HttpChannel.onRequest()` that calls the `Handler` chain starting from the `Server` instance, that eventually calls your web application code.
|
||||
When enough of the HTTP request is arrived, the `Connection` calls `HttpChannel.onRequest()`.
|
||||
|
||||
`HttpChannel.onRequest()` calls the xref:pg-server-http-request-customizers[request customizers], that allow to customize the request and/or the response headers on a per-``Connector`` basis.
|
||||
|
||||
After request customization, if any, the `Handler` chain is invoked, starting from the `Server` instance, and eventually your web application code is invoked.
|
||||
|
||||
[[pg-server-http-request-processing-events]]
|
||||
===== Request Processing Events
|
||||
|
@ -135,42 +139,8 @@ A typical case is to know exactly _when_ the HTTP request/response processing st
|
|||
|
||||
This is conveniently implemented by `org.eclipse.jetty.server.handler.EventsHandler`, described in more details in xref:pg-server-http-handler-use-events[this section].
|
||||
|
||||
[[pg-server-http-request-logging]]
|
||||
==== Request Logging
|
||||
|
||||
HTTP requests and responses can be logged to provide data that can be later analyzed with other tools.
|
||||
These tools can provide information such as the most frequently accessed request URIs, the response status codes, the request/response content lengths, geographical information about the clients, etc.
|
||||
|
||||
The default request/response log line format is the link:https://en.wikipedia.org/wiki/Common_Log_Format[NCSA Format] extended with referrer data and user-agent data.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Typically, the extended NCSA format is the is enough and it's the standard used and understood by most log parsing tools and monitoring tools.
|
||||
|
||||
To customize the request/response log line format see the link:{javadoc-url}/org/eclipse/jetty/server/CustomRequestLog.html[`CustomRequestLog` javadocs].
|
||||
====
|
||||
|
||||
Request logging can be enabled at the `Server` level.
|
||||
|
||||
The request logging output can be directed to an SLF4J logger named `"org.eclipse.jetty.server.RequestLog"` at `INFO` level, and therefore to any logging library implementation of your choice (see also xref:pg-troubleshooting-logging[this section] about logging).
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java[tags=serverRequestLogSLF4J]
|
||||
----
|
||||
|
||||
Alternatively, the request logging output can be directed to a daily rolling file of your choice, and the file name must contain `yyyy_MM_dd` so that rolled over files retain their date:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java[tags=serverRequestLogFile]
|
||||
----
|
||||
|
||||
For maximum flexibility, you can log to multiple ``RequestLog``s using class `RequestLog.Collection`, for example by logging with different formats or to different outputs.
|
||||
|
||||
You can use `CustomRequestLog` with a custom `RequestLog.Writer` to direct the request logging output to your custom targets (for example, an RDBMS).
|
||||
You can implement your own `RequestLog` if you want to have functionalities that are not implemented by `CustomRequestLog`.
|
||||
|
||||
include::server-http-request-logging.adoc[]
|
||||
include::server-http-request-customizers.adoc[]
|
||||
include::server-http-connector.adoc[]
|
||||
include::server-http-handler.adoc[]
|
||||
include::server-http-session.adoc[]
|
||||
|
|
|
@ -1593,4 +1593,32 @@ public class HTTPServerDocs
|
|||
}
|
||||
// end::continue100[]
|
||||
}
|
||||
|
||||
public void requestCustomizer() throws Exception
|
||||
{
|
||||
// tag::requestCustomizer[]
|
||||
Server server = new Server();
|
||||
|
||||
// Configure the secure connector.
|
||||
HttpConfiguration httpsConfig = new HttpConfiguration();
|
||||
|
||||
// Add the SecureRequestCustomizer.
|
||||
httpsConfig.addCustomizer(new SecureRequestCustomizer());
|
||||
|
||||
// Configure the SslContextFactory with the KeyStore information.
|
||||
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
|
||||
sslContextFactory.setKeyStorePath("/path/to/keystore");
|
||||
sslContextFactory.setKeyStorePassword("secret");
|
||||
// Configure the Connector to speak HTTP/1.1 and HTTP/2.
|
||||
HttpConnectionFactory h1 = new HttpConnectionFactory(httpsConfig);
|
||||
HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpsConfig);
|
||||
ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
|
||||
alpn.setDefaultProtocol(h1.getProtocol());
|
||||
SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, alpn.getProtocol());
|
||||
ServerConnector connector = new ServerConnector(server, ssl, alpn, h2, h1);
|
||||
server.addConnector(connector);
|
||||
|
||||
server.start();
|
||||
// end::requestCustomizer[]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -896,8 +896,8 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable add(String name, String value)
|
||||
{
|
||||
if (value == null)
|
||||
throw new IllegalArgumentException("null value");
|
||||
Objects.requireNonNull(name);
|
||||
Objects.requireNonNull(value);
|
||||
return add(new HttpField(name, value));
|
||||
}
|
||||
|
||||
|
@ -912,6 +912,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable add(String name, long value)
|
||||
{
|
||||
Objects.requireNonNull(name);
|
||||
return add(new HttpField.LongValueHttpField(name, value));
|
||||
}
|
||||
|
||||
|
@ -926,6 +927,8 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable add(HttpHeader header, HttpHeaderValue value)
|
||||
{
|
||||
Objects.requireNonNull(header);
|
||||
Objects.requireNonNull(value);
|
||||
return add(header, value.toString());
|
||||
}
|
||||
|
||||
|
@ -940,8 +943,8 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable add(HttpHeader header, String value)
|
||||
{
|
||||
if (value == null)
|
||||
throw new IllegalArgumentException("null value");
|
||||
Objects.requireNonNull(header);
|
||||
Objects.requireNonNull(value);
|
||||
return add(new HttpField(header, value));
|
||||
}
|
||||
|
||||
|
@ -956,6 +959,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable add(HttpHeader header, long value)
|
||||
{
|
||||
Objects.requireNonNull(header);
|
||||
return add(new HttpField.LongValueHttpField(header, value));
|
||||
}
|
||||
|
||||
|
@ -967,6 +971,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable add(HttpField field)
|
||||
{
|
||||
Objects.requireNonNull(field);
|
||||
ListIterator<HttpField> i = listIterator(size());
|
||||
i.add(field);
|
||||
return this;
|
||||
|
@ -998,8 +1003,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
default Mutable add(String name, List<String> list)
|
||||
{
|
||||
Objects.requireNonNull(name);
|
||||
if (list == null)
|
||||
throw new IllegalArgumentException("null list");
|
||||
Objects.requireNonNull(list);
|
||||
if (list.isEmpty())
|
||||
return this;
|
||||
if (list.size() == 1)
|
||||
|
@ -1022,6 +1026,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable addCSV(HttpHeader header, String... values)
|
||||
{
|
||||
Objects.requireNonNull(header);
|
||||
QuotedCSV existing = null;
|
||||
for (HttpField f : this)
|
||||
{
|
||||
|
@ -1049,6 +1054,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable addCSV(String name, String... values)
|
||||
{
|
||||
Objects.requireNonNull(name);
|
||||
QuotedCSV existing = null;
|
||||
for (HttpField f : this)
|
||||
{
|
||||
|
@ -1076,6 +1082,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable addDateField(String name, long date)
|
||||
{
|
||||
Objects.requireNonNull(name);
|
||||
add(name, DateGenerator.formatDate(date));
|
||||
return this;
|
||||
}
|
||||
|
@ -1105,6 +1112,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default void ensureField(HttpField field)
|
||||
{
|
||||
Objects.requireNonNull(field);
|
||||
HttpHeader header = field.getHeader();
|
||||
// Is the field value multi valued?
|
||||
if (field.getValue().indexOf(',') < 0)
|
||||
|
@ -1136,6 +1144,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable put(HttpField field)
|
||||
{
|
||||
Objects.requireNonNull(field);
|
||||
boolean put = false;
|
||||
ListIterator<HttpField> i = listIterator();
|
||||
while (i.hasNext())
|
||||
|
@ -1170,6 +1179,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable put(String name, String value)
|
||||
{
|
||||
Objects.requireNonNull(name);
|
||||
if (value == null)
|
||||
return remove(name);
|
||||
return put(new HttpField(name, value));
|
||||
|
@ -1186,6 +1196,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable put(HttpHeader header, HttpHeaderValue value)
|
||||
{
|
||||
Objects.requireNonNull(header);
|
||||
if (value == null)
|
||||
return remove(header);
|
||||
return put(new HttpField(header, value.toString()));
|
||||
|
@ -1202,6 +1213,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable put(HttpHeader header, String value)
|
||||
{
|
||||
Objects.requireNonNull(header);
|
||||
if (value == null)
|
||||
return remove(header);
|
||||
return put(new HttpField(header, value));
|
||||
|
@ -1241,6 +1253,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable putDate(HttpHeader name, long date)
|
||||
{
|
||||
Objects.requireNonNull(name);
|
||||
return put(name, DateGenerator.formatDate(date));
|
||||
}
|
||||
|
||||
|
@ -1256,6 +1269,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable putDate(String name, long date)
|
||||
{
|
||||
Objects.requireNonNull(name);
|
||||
return put(name, DateGenerator.formatDate(date));
|
||||
}
|
||||
|
||||
|
@ -1269,6 +1283,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable put(HttpHeader header, long value)
|
||||
{
|
||||
Objects.requireNonNull(header);
|
||||
if (value == 0 && header == HttpHeader.CONTENT_LENGTH)
|
||||
return put(HttpFields.CONTENT_LENGTH_0);
|
||||
return put(new HttpField.LongValueHttpField(header, value));
|
||||
|
@ -1284,6 +1299,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable put(String name, long value)
|
||||
{
|
||||
Objects.requireNonNull(name);
|
||||
if (value == 0 && HttpHeader.CONTENT_LENGTH.is(name))
|
||||
return put(HttpFields.CONTENT_LENGTH_0);
|
||||
return put(new HttpField.LongValueHttpField(name, value));
|
||||
|
@ -1367,7 +1383,9 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable computeField(HttpHeader header, BiFunction<HttpHeader, List<HttpField>, HttpField> computeFn)
|
||||
{
|
||||
return put(computeFn.apply(header, stream().filter(f -> f.getHeader() == header).collect(Collectors.toList())));
|
||||
Objects.requireNonNull(header);
|
||||
HttpField result = computeFn.apply(header, stream().filter(f -> f.getHeader() == header).toList());
|
||||
return result != null ? put(result) : remove(header);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1380,7 +1398,9 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable computeField(String name, BiFunction<String, List<HttpField>, HttpField> computeFn)
|
||||
{
|
||||
return put(computeFn.apply(name, stream().filter(f -> f.is(name)).collect(Collectors.toList())));
|
||||
Objects.requireNonNull(name);
|
||||
HttpField result = computeFn.apply(name, stream().filter(f -> f.is(name)).toList());
|
||||
return result != null ? put(result) : remove(name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1391,6 +1411,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable remove(HttpHeader header)
|
||||
{
|
||||
Objects.requireNonNull(header);
|
||||
Iterator<HttpField> i = iterator();
|
||||
while (i.hasNext())
|
||||
{
|
||||
|
@ -1428,6 +1449,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
*/
|
||||
default Mutable remove(String name)
|
||||
{
|
||||
Objects.requireNonNull(name);
|
||||
for (ListIterator<HttpField> i = listIterator(); i.hasNext(); )
|
||||
{
|
||||
HttpField f = i.next();
|
||||
|
@ -1656,6 +1678,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
@Override
|
||||
public Mutable put(HttpField field)
|
||||
{
|
||||
Objects.requireNonNull(field);
|
||||
// rewrite put to ensure that removes are called before replace
|
||||
int put = -1;
|
||||
ListIterator<HttpField> i = _fields.listIterator();
|
||||
|
@ -1675,7 +1698,7 @@ public interface HttpFields extends Iterable<HttpField>, Supplier<HttpFields>
|
|||
{
|
||||
field = onAddField(field);
|
||||
if (field != null)
|
||||
add(field);
|
||||
_fields.add(field);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1004,7 +1004,7 @@ public class HttpFieldsTest
|
|||
public void testAddNullValueList()
|
||||
{
|
||||
HttpFields.Mutable fields = HttpFields.build();
|
||||
assertThrows(IllegalArgumentException.class, () -> fields.add("name", (List<String>)null));
|
||||
assertThrows(NullPointerException.class, () -> fields.add("name", (List<String>)null));
|
||||
assertThat(fields.size(), is(0));
|
||||
List<String> list = new ArrayList<>();
|
||||
fields.add("name", list);
|
||||
|
@ -1374,4 +1374,56 @@ public class HttpFieldsTest
|
|||
fields.ensureField(new HttpField("Test", "three, four"));
|
||||
assertThat(fields.stream().map(HttpField::toString).collect(Collectors.toList()), contains("Test: one, two, three, four"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrapperComputeFieldCallingOnField()
|
||||
{
|
||||
var wrapper = new HttpFields.Mutable.Wrapper(HttpFields.build())
|
||||
{
|
||||
final List<String> actions = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public HttpField onAddField(HttpField field)
|
||||
{
|
||||
actions.add("onAddField");
|
||||
return super.onAddField(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onRemoveField(HttpField field)
|
||||
{
|
||||
actions.add("onRemoveField");
|
||||
return super.onRemoveField(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpField onReplaceField(HttpField oldField, HttpField newField)
|
||||
{
|
||||
actions.add("onReplaceField");
|
||||
return super.onReplaceField(oldField, newField);
|
||||
}
|
||||
};
|
||||
|
||||
wrapper.computeField("non-existent", (name, httpFields) -> null);
|
||||
assertThat(wrapper.size(), is(0));
|
||||
assertThat(wrapper.actions, is(List.of()));
|
||||
|
||||
wrapper.computeField("non-existent", (name, httpFields) -> new HttpField("non-existent", "a"));
|
||||
wrapper.computeField("non-existent", (name, httpFields) -> new HttpField("non-existent", "b"));
|
||||
wrapper.computeField("non-existent", (name, httpFields) -> null);
|
||||
assertThat(wrapper.size(), is(0));
|
||||
assertThat(wrapper.actions, is(List.of("onAddField", "onReplaceField", "onRemoveField")));
|
||||
wrapper.actions.clear();
|
||||
|
||||
wrapper.computeField(HttpHeader.VARY, (name, httpFields) -> null);
|
||||
assertThat(wrapper.size(), is(0));
|
||||
assertThat(wrapper.actions, is(List.of()));
|
||||
|
||||
wrapper.computeField(HttpHeader.VARY, (name, httpFields) -> new HttpField(HttpHeader.VARY, "a"));
|
||||
wrapper.computeField(HttpHeader.VARY, (name, httpFields) -> new HttpField(HttpHeader.VARY, "b"));
|
||||
wrapper.computeField(HttpHeader.VARY, (name, httpFields) -> null);
|
||||
assertThat(wrapper.size(), is(0));
|
||||
assertThat(wrapper.actions, is(List.of("onAddField", "onReplaceField", "onRemoveField")));
|
||||
wrapper.actions.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,8 +99,8 @@ public class HttpGeneratorClientTest
|
|||
|
||||
HttpFields.Mutable fields = HttpFields.build();
|
||||
fields.add("Host", "something");
|
||||
assertThrows(IllegalArgumentException.class, () -> fields.add("Null", (String)null));
|
||||
assertThrows(IllegalArgumentException.class, () -> fields.add("Null", (List<String>)null));
|
||||
assertThrows(NullPointerException.class, () -> fields.add("Null", (String)null));
|
||||
assertThrows(NullPointerException.class, () -> fields.add("Null", (List<String>)null));
|
||||
fields.add("Empty", "");
|
||||
RequestInfo info = new RequestInfo("GET", "/index.html", fields);
|
||||
assertFalse(gen.isChunking());
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-core</artifactId>
|
||||
<version>12.0.9-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>jetty-maven</artifactId>
|
||||
<name>Core :: Maven</name>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.maven</bundle-symbolic-name>
|
||||
<spotbugs.onlyAnalyze>org.eclipse.jetty.maven.*</spotbugs.onlyAnalyze>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.plugin-tools</groupId>
|
||||
<artifactId>maven-plugin-tools-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.plexus</groupId>
|
||||
<artifactId>plexus-xml</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-api-xml</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-xml-impl</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-xml-meta</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-xml</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-artifact</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-model</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-plugin-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-slf4j-impl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>@{argLine} ${jetty.surefire.argLine}
|
||||
--add-reads org.eclipse.jetty.maven=org.eclipse.jetty.logging</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,208 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* JettyForkedChild
|
||||
*
|
||||
* This is the class that is executed when the jetty maven plugin
|
||||
* forks a process when DeploymentMode=FORKED.
|
||||
*/
|
||||
public abstract class AbstractForkedChild extends ContainerLifeCycle
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractForkedChild.class);
|
||||
|
||||
protected AbstractJettyEmbedder jetty;
|
||||
protected File tokenFile; // TODO: convert to Path
|
||||
protected Scanner scanner;
|
||||
protected File webAppPropsFile; // TODO: convert to Path
|
||||
protected int scanInterval;
|
||||
|
||||
/**
|
||||
* @param args arguments that were passed to main
|
||||
* @throws Exception if unable to configure
|
||||
*/
|
||||
public AbstractForkedChild(String[] args)
|
||||
throws Exception
|
||||
{
|
||||
jetty = newJettyEmbedder();
|
||||
configure(args);
|
||||
}
|
||||
|
||||
public AbstractJettyEmbedder getJettyEmbedder()
|
||||
{
|
||||
return jetty;
|
||||
}
|
||||
|
||||
protected abstract AbstractJettyEmbedder newJettyEmbedder();
|
||||
|
||||
/**
|
||||
* Based on the args passed to the program, configure jetty.
|
||||
*
|
||||
* @param args args that were passed to the program.
|
||||
* @throws Exception if unable to load webprops
|
||||
*/
|
||||
public void configure(String[] args)
|
||||
throws Exception
|
||||
{
|
||||
Map<String, String> jettyProperties = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < args.length; i++)
|
||||
{
|
||||
//--stop-port
|
||||
if ("--stop-port".equals(args[i]))
|
||||
{
|
||||
jetty.setStopPort(Integer.parseInt(args[++i]));
|
||||
continue;
|
||||
}
|
||||
|
||||
//--stop-key
|
||||
if ("--stop-key".equals(args[i]))
|
||||
{
|
||||
jetty.setStopKey(args[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
//--jettyXml
|
||||
if ("--jetty-xml".equals(args[i]))
|
||||
{
|
||||
List<File> jettyXmls = new ArrayList<>();
|
||||
String[] names = StringUtil.csvSplit(args[++i]);
|
||||
for (int j = 0; names != null && j < names.length; j++)
|
||||
{
|
||||
jettyXmls.add(new File(names[j].trim()));
|
||||
}
|
||||
jetty.setJettyXmlFiles(jettyXmls);
|
||||
continue;
|
||||
}
|
||||
//--webprops
|
||||
if ("--webprops".equals(args[i]))
|
||||
{
|
||||
webAppPropsFile = new File(args[++i].trim());
|
||||
jetty.setWebAppProperties(loadWebAppProps());
|
||||
continue;
|
||||
}
|
||||
|
||||
//--token
|
||||
if ("--token".equals(args[i]))
|
||||
{
|
||||
tokenFile = new File(args[++i].trim());
|
||||
continue;
|
||||
}
|
||||
|
||||
if ("--scanInterval".equals(args[i]))
|
||||
{
|
||||
scanInterval = Integer.parseInt(args[++i].trim());
|
||||
scanner = new Scanner();
|
||||
scanner.setReportExistingFilesOnStartup(false);
|
||||
scanner.setScanInterval(scanInterval);
|
||||
scanner.addListener(new Scanner.BulkListener()
|
||||
{
|
||||
public void filesChanged(Set<String> changes)
|
||||
{
|
||||
if (!Objects.isNull(scanner))
|
||||
{
|
||||
try
|
||||
{
|
||||
scanner.stop();
|
||||
jetty.redeployWebApp(loadWebAppProps());
|
||||
scanner.start();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.error("Error reconfiguring/restarting webapp after change in watched files", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!Objects.isNull(webAppPropsFile))
|
||||
scanner.addFile(webAppPropsFile.toPath());
|
||||
continue;
|
||||
}
|
||||
|
||||
//assume everything else is a jetty property to be passed in
|
||||
String[] tmp = args[i].trim().split("=");
|
||||
if (tmp.length == 2)
|
||||
{
|
||||
jettyProperties.put(tmp[0], tmp[1]);
|
||||
}
|
||||
}
|
||||
|
||||
jetty.setJettyProperties(jettyProperties);
|
||||
jetty.setExitVm(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load properties from a file describing the webapp if one is
|
||||
* present.
|
||||
*
|
||||
* @return file contents as properties
|
||||
* @throws FileNotFoundException if there is a file not found problem
|
||||
* @throws IOException if there is an IO problem
|
||||
*/
|
||||
protected Properties loadWebAppProps() throws FileNotFoundException, IOException
|
||||
{
|
||||
Properties props = new Properties();
|
||||
if (Objects.nonNull(webAppPropsFile))
|
||||
props.load(new FileInputStream(webAppPropsFile));
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a jetty instance and webapp. This thread will
|
||||
* wait until jetty exits.
|
||||
*/
|
||||
public void doStart()
|
||||
throws Exception
|
||||
{
|
||||
super.doStart();
|
||||
|
||||
//Start the embedded jetty instance
|
||||
jetty.start();
|
||||
|
||||
//touch file to signify start of jetty
|
||||
Path tokenPath = tokenFile.toPath();
|
||||
Files.createFile(tokenPath);
|
||||
|
||||
//Start a watcher on a file that will change if the
|
||||
//webapp is regenerated; stop the webapp, apply the
|
||||
//properties and restart it.
|
||||
if (scanner != null)
|
||||
scanner.start();
|
||||
|
||||
//wait for jetty to finish
|
||||
jetty.join();
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
|
@ -0,0 +1,428 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
|
||||
/**
|
||||
* AbstractHomeForker
|
||||
*
|
||||
* Unpacks a jetty-home and configures it with a base that allows it
|
||||
* to run an unassembled webapp.
|
||||
*/
|
||||
public abstract class AbstractHomeForker extends AbstractForker
|
||||
{
|
||||
protected String contextXml;
|
||||
|
||||
/**
|
||||
* Location of existing jetty home directory
|
||||
*/
|
||||
protected File jettyHome;
|
||||
|
||||
/**
|
||||
* Zip of jetty-home
|
||||
*/
|
||||
protected File jettyHomeZip;
|
||||
|
||||
/**
|
||||
* Location of existing jetty base directory
|
||||
*/
|
||||
protected File jettyBase;
|
||||
|
||||
protected File baseDir;
|
||||
|
||||
/**
|
||||
* Optional list of other modules to
|
||||
* activate.
|
||||
*/
|
||||
protected String[] modules;
|
||||
|
||||
/*
|
||||
* Optional jetty commands
|
||||
*/
|
||||
protected String jettyOptions;
|
||||
|
||||
protected List<File> libExtJarFiles;
|
||||
protected Path modulesPath;
|
||||
protected Path etcPath;
|
||||
protected Path libPath;
|
||||
protected Path webappPath;
|
||||
protected Path mavenLibPath;
|
||||
protected String version;
|
||||
protected String environment;
|
||||
|
||||
public void setVersion(String version)
|
||||
{
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public void setJettyOptions(String jettyOptions)
|
||||
{
|
||||
this.jettyOptions = jettyOptions;
|
||||
}
|
||||
|
||||
public String getJettyOptions()
|
||||
{
|
||||
return jettyOptions;
|
||||
}
|
||||
|
||||
public List<File> getLibExtJarFiles()
|
||||
{
|
||||
return libExtJarFiles;
|
||||
}
|
||||
|
||||
public void setLibExtJarFiles(List<File> libExtJarFiles)
|
||||
{
|
||||
this.libExtJarFiles = libExtJarFiles;
|
||||
}
|
||||
|
||||
public File getJettyHome()
|
||||
{
|
||||
return jettyHome;
|
||||
}
|
||||
|
||||
public void setJettyHome(File jettyHome)
|
||||
{
|
||||
this.jettyHome = jettyHome;
|
||||
}
|
||||
|
||||
public File getJettyBase()
|
||||
{
|
||||
return jettyBase;
|
||||
}
|
||||
|
||||
public void setJettyBase(File jettyBase)
|
||||
{
|
||||
this.jettyBase = jettyBase;
|
||||
}
|
||||
|
||||
public String[] getModules()
|
||||
{
|
||||
return modules;
|
||||
}
|
||||
|
||||
public void setModules(String[] modules)
|
||||
{
|
||||
this.modules = modules;
|
||||
}
|
||||
|
||||
public String getContextXmlFile()
|
||||
{
|
||||
return contextXml;
|
||||
}
|
||||
|
||||
public void setContextXml(String contextXml)
|
||||
{
|
||||
this.contextXml = contextXml;
|
||||
}
|
||||
|
||||
public File getJettyHomeZip()
|
||||
{
|
||||
return jettyHomeZip;
|
||||
}
|
||||
|
||||
public void setJettyHomeZip(File jettyHomeZip)
|
||||
{
|
||||
this.jettyHomeZip = jettyHomeZip;
|
||||
}
|
||||
|
||||
public File getBaseDir()
|
||||
{
|
||||
return baseDir;
|
||||
}
|
||||
|
||||
public void setBaseDir(File baseDir)
|
||||
{
|
||||
this.baseDir = baseDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProcessBuilder createCommand()
|
||||
{
|
||||
List<String> cmd = new ArrayList<>();
|
||||
cmd.add("java");
|
||||
|
||||
//add any args to the jvm
|
||||
if (StringUtil.isNotBlank(jvmArgs))
|
||||
{
|
||||
Arrays.stream(jvmArgs.split(" ")).filter(a -> StringUtil.isNotBlank(a)).forEach((a) -> cmd.add(a.trim()));
|
||||
}
|
||||
|
||||
cmd.add("-jar");
|
||||
cmd.add(new File(jettyHome, "start.jar").getAbsolutePath());
|
||||
|
||||
if (systemProperties != null)
|
||||
{
|
||||
for (Map.Entry<String, String> e : systemProperties.entrySet())
|
||||
{
|
||||
cmd.add("-D" + e.getKey() + "=" + e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
cmd.add("-DSTOP.PORT=" + stopPort);
|
||||
if (stopKey != null)
|
||||
cmd.add("-DSTOP.KEY=" + stopKey);
|
||||
|
||||
//set up enabled jetty modules
|
||||
StringBuilder tmp = new StringBuilder();
|
||||
tmp.append("--module=");
|
||||
tmp.append("server,http," + environment + "-webapp," + environment + "-deploy");
|
||||
if (modules != null)
|
||||
{
|
||||
for (String m : modules)
|
||||
{
|
||||
if (tmp.indexOf(m) < 0)
|
||||
tmp.append("," + m);
|
||||
}
|
||||
}
|
||||
|
||||
if (libExtJarFiles != null && !libExtJarFiles.isEmpty() && tmp.indexOf("ext") < 0)
|
||||
tmp.append(",ext");
|
||||
tmp.append("," + environment + "-maven");
|
||||
cmd.add(tmp.toString());
|
||||
|
||||
//put any other jetty options onto the command line
|
||||
if (StringUtil.isNotBlank(jettyOptions))
|
||||
{
|
||||
Arrays.stream(jettyOptions.split(" ")).filter(a -> StringUtil.isNotBlank(a)).forEach((a) -> cmd.add(a.trim()));
|
||||
}
|
||||
|
||||
//put any jetty properties onto the command line
|
||||
if (jettyProperties != null)
|
||||
{
|
||||
for (Map.Entry<String, String> e : jettyProperties.entrySet())
|
||||
{
|
||||
cmd.add(e.getKey() + "=" + e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
//existence of this file signals process started
|
||||
cmd.add("jetty.token.file=" + tokenFile.getAbsolutePath().toString());
|
||||
|
||||
ProcessBuilder builder = new ProcessBuilder(cmd);
|
||||
builder.directory(workDir);
|
||||
|
||||
PluginLog.getLog().info("Home process starting");
|
||||
|
||||
//set up extra environment vars if there are any
|
||||
if (!env.isEmpty())
|
||||
builder.environment().putAll(env);
|
||||
|
||||
if (waitForChild)
|
||||
builder.inheritIO();
|
||||
else
|
||||
{
|
||||
builder.redirectOutput(jettyOutputFile);
|
||||
builder.redirectErrorStream(true);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doStart() throws Exception
|
||||
{
|
||||
//set up a jetty-home
|
||||
configureJettyHome();
|
||||
|
||||
if (jettyHome == null || !jettyHome.exists())
|
||||
throw new IllegalStateException("No jetty home");
|
||||
|
||||
//set up a jetty-base
|
||||
configureJettyBase();
|
||||
|
||||
//convert the webapp to properties
|
||||
generateWebAppPropertiesFile();
|
||||
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
protected void redeployWebApp()
|
||||
throws Exception
|
||||
{
|
||||
generateWebAppPropertiesFile();
|
||||
webappPath.resolve("maven.xml").toFile().setLastModified(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
protected abstract void generateWebAppPropertiesFile() throws Exception;
|
||||
|
||||
/**
|
||||
* Create or configure a jetty base.
|
||||
*/
|
||||
private void configureJettyBase() throws Exception
|
||||
{
|
||||
if (jettyBase != null && !jettyBase.exists())
|
||||
throw new IllegalStateException(jettyBase.getAbsolutePath() + " does not exist");
|
||||
|
||||
File targetJettyBase = new File(baseDir, "jetty-base");
|
||||
Path targetBasePath = targetJettyBase.toPath();
|
||||
if (Files.exists(targetBasePath))
|
||||
IO.delete(targetJettyBase);
|
||||
|
||||
targetJettyBase.mkdirs();
|
||||
|
||||
//jetty-base will be the working directory for the forked command
|
||||
workDir = targetJettyBase;
|
||||
|
||||
//if there is an existing jetty base, copy parts of it
|
||||
if (jettyBase != null)
|
||||
{
|
||||
Path jettyBasePath = jettyBase.toPath();
|
||||
|
||||
final File contextXmlFile = (contextXml == null ? null : FileSystems.getDefault().getPath(contextXml).toFile());
|
||||
|
||||
//copy the existing jetty base
|
||||
Files.walkFileTree(jettyBasePath, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
|
||||
new SimpleFileVisitor<Path>()
|
||||
{
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException
|
||||
{
|
||||
Path targetDir = targetBasePath.resolve(jettyBasePath.relativize(dir));
|
||||
try
|
||||
{
|
||||
Files.copy(dir, targetDir);
|
||||
}
|
||||
catch (FileAlreadyExistsException e)
|
||||
{
|
||||
if (!Files.isDirectory(targetDir)) //ignore attempt to recreate dir
|
||||
throw e;
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException
|
||||
{
|
||||
if (contextXmlFile != null && Files.isSameFile(contextXmlFile.toPath(), file))
|
||||
return FileVisitResult.CONTINUE; //skip copying the context xml file
|
||||
Files.copy(file, targetBasePath.resolve(jettyBasePath.relativize(file)));
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//make the jetty base structure
|
||||
modulesPath = Files.createDirectories(targetBasePath.resolve("modules"));
|
||||
etcPath = Files.createDirectories(targetBasePath.resolve("etc"));
|
||||
libPath = Files.createDirectories(targetBasePath.resolve("lib"));
|
||||
webappPath = Files.createDirectories(targetBasePath.resolve("webapps"));
|
||||
mavenLibPath = Files.createDirectories(libPath.resolve(environment + "-maven"));
|
||||
|
||||
//copy in the jetty-${ee}-maven-plugin jar
|
||||
URI thisJar = TypeUtil.getLocationOfClass(this.getClass());
|
||||
if (thisJar == null)
|
||||
throw new IllegalStateException("Can't find jar for jetty-" + environment + "-maven-plugin");
|
||||
|
||||
try (InputStream jarStream = thisJar.toURL().openStream();
|
||||
FileOutputStream fileStream = new FileOutputStream(mavenLibPath.resolve("jetty-" + environment + "-maven-plugin.jar").toFile()))
|
||||
{
|
||||
IO.copy(jarStream, fileStream);
|
||||
}
|
||||
|
||||
//copy in the jetty-maven.jar for common classes
|
||||
URI commonJar = TypeUtil.getLocationOfClass(AbstractHomeForker.class);
|
||||
if (commonJar == null)
|
||||
throw new IllegalStateException("Can't find jar for jetty-maven common classes");
|
||||
try (InputStream jarStream = commonJar.toURL().openStream();
|
||||
FileOutputStream fileStream = new FileOutputStream(mavenLibPath.resolve("jetty-maven.jar").toFile()))
|
||||
{
|
||||
IO.copy(jarStream, fileStream);
|
||||
}
|
||||
|
||||
//copy in the maven-${ee}.xml webapp file
|
||||
String mavenXml = "maven-" + environment + ".xml";
|
||||
try (InputStream mavenXmlStream = getClass().getClassLoader().getResourceAsStream(mavenXml);
|
||||
FileOutputStream fileStream = new FileOutputStream(webappPath.resolve(mavenXml).toFile()))
|
||||
{
|
||||
IO.copy(mavenXmlStream, fileStream);
|
||||
}
|
||||
|
||||
Files.writeString(webappPath.resolve("maven-" + environment + ".properties"), "environment=" + environment);
|
||||
|
||||
//copy in the ${ee}-maven.mod file
|
||||
String mavenMod = environment + "-maven.mod";
|
||||
try (InputStream mavenModStream = getClass().getClassLoader().getResourceAsStream(mavenMod);
|
||||
FileOutputStream fileStream = new FileOutputStream(modulesPath.resolve(mavenMod).toFile()))
|
||||
{
|
||||
IO.copy(mavenModStream, fileStream);
|
||||
}
|
||||
|
||||
//copy in the jetty-${ee}-maven.xml file
|
||||
String jettyMavenXml = "jetty-" + environment + "-maven.xml";
|
||||
try (InputStream jettyMavenStream = getClass().getClassLoader().getResourceAsStream(jettyMavenXml);
|
||||
FileOutputStream fileStream = new FileOutputStream(etcPath.resolve(jettyMavenXml).toFile()))
|
||||
{
|
||||
IO.copy(jettyMavenStream, fileStream);
|
||||
}
|
||||
|
||||
//if there were plugin dependencies, copy them into lib/ext
|
||||
if (libExtJarFiles != null && !libExtJarFiles.isEmpty())
|
||||
{
|
||||
Path libExtPath = Files.createDirectories(libPath.resolve("ext"));
|
||||
for (File f : libExtJarFiles)
|
||||
{
|
||||
try (InputStream jarStream = new FileInputStream(f);
|
||||
FileOutputStream fileStream = new FileOutputStream(libExtPath.resolve(f.getName()).toFile()))
|
||||
{
|
||||
IO.copy(jarStream, fileStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void configureJettyHome()
|
||||
throws Exception
|
||||
{
|
||||
if (jettyHome == null && jettyHomeZip == null)
|
||||
throw new IllegalStateException("No jettyHome");
|
||||
|
||||
if (baseDir == null)
|
||||
throw new IllegalStateException("No baseDir");
|
||||
|
||||
if (jettyHome == null)
|
||||
{
|
||||
try (ResourceFactory.Closeable resourceFactory = ResourceFactory.closeable())
|
||||
{
|
||||
Resource res = resourceFactory.newJarFileResource(jettyHomeZip.toPath().toUri());
|
||||
res.copyTo(baseDir.toPath());
|
||||
}
|
||||
//zip will unpack to target/jetty-home-<VERSION>
|
||||
jettyHome = new File(baseDir, "jetty-home-" + version);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,284 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.eclipse.jetty.security.LoginService;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ShutdownMonitor;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
|
||||
/**
|
||||
* AbstractJettyEmbedder
|
||||
* Starts jetty within the current process.
|
||||
*/
|
||||
public abstract class AbstractJettyEmbedder extends ContainerLifeCycle
|
||||
{
|
||||
protected List<ContextHandler> contextHandlers;
|
||||
protected List<LoginService> loginServices;
|
||||
protected RequestLog requestLog;
|
||||
protected MavenServerConnector httpConnector;
|
||||
protected Server server;
|
||||
protected boolean exitVm;
|
||||
protected boolean stopAtShutdown;
|
||||
protected List<File> jettyXmlFiles;
|
||||
protected Map<String, String> jettyProperties;
|
||||
protected ShutdownMonitor shutdownMonitor;
|
||||
protected int stopPort;
|
||||
protected String stopKey;
|
||||
protected String contextXml;
|
||||
protected Properties webAppProperties;
|
||||
|
||||
public List<ContextHandler> getContextHandlers()
|
||||
{
|
||||
return contextHandlers;
|
||||
}
|
||||
|
||||
public void setContextHandlers(List<ContextHandler> contextHandlers)
|
||||
{
|
||||
if (contextHandlers == null)
|
||||
this.contextHandlers = null;
|
||||
else
|
||||
this.contextHandlers = new ArrayList<>(contextHandlers);
|
||||
}
|
||||
|
||||
public List<LoginService> getLoginServices()
|
||||
{
|
||||
return loginServices;
|
||||
}
|
||||
|
||||
public void setLoginServices(List<LoginService> loginServices)
|
||||
{
|
||||
if (loginServices == null)
|
||||
this.loginServices = null;
|
||||
else
|
||||
this.loginServices = new ArrayList<>(loginServices);
|
||||
}
|
||||
|
||||
public RequestLog getRequestLog()
|
||||
{
|
||||
return requestLog;
|
||||
}
|
||||
|
||||
public void setRequestLog(RequestLog requestLog)
|
||||
{
|
||||
this.requestLog = requestLog;
|
||||
}
|
||||
|
||||
public MavenServerConnector getHttpConnector()
|
||||
{
|
||||
return httpConnector;
|
||||
}
|
||||
|
||||
public void setHttpConnector(MavenServerConnector httpConnector)
|
||||
{
|
||||
this.httpConnector = httpConnector;
|
||||
}
|
||||
|
||||
public Server getServer()
|
||||
{
|
||||
return server;
|
||||
}
|
||||
|
||||
public void setServer(Server server)
|
||||
{
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public boolean isExitVm()
|
||||
{
|
||||
return exitVm;
|
||||
}
|
||||
|
||||
public void setExitVm(boolean exitVm)
|
||||
{
|
||||
this.exitVm = exitVm;
|
||||
}
|
||||
|
||||
public boolean isStopAtShutdown()
|
||||
{
|
||||
return stopAtShutdown;
|
||||
}
|
||||
|
||||
public void setStopAtShutdown(boolean stopAtShutdown)
|
||||
{
|
||||
this.stopAtShutdown = stopAtShutdown;
|
||||
}
|
||||
|
||||
public List<File> getJettyXmlFiles()
|
||||
{
|
||||
return jettyXmlFiles;
|
||||
}
|
||||
|
||||
public void setJettyXmlFiles(List<File> jettyXmlFiles)
|
||||
{
|
||||
this.jettyXmlFiles = jettyXmlFiles;
|
||||
}
|
||||
|
||||
public Map<String, String> getJettyProperties()
|
||||
{
|
||||
return jettyProperties;
|
||||
}
|
||||
|
||||
public void setJettyProperties(Map<String, String> jettyProperties)
|
||||
{
|
||||
this.jettyProperties = jettyProperties;
|
||||
}
|
||||
|
||||
public ShutdownMonitor getShutdownMonitor()
|
||||
{
|
||||
return shutdownMonitor;
|
||||
}
|
||||
|
||||
public void setShutdownMonitor(ShutdownMonitor shutdownMonitor)
|
||||
{
|
||||
this.shutdownMonitor = shutdownMonitor;
|
||||
}
|
||||
|
||||
public int getStopPort()
|
||||
{
|
||||
return stopPort;
|
||||
}
|
||||
|
||||
public void setStopPort(int stopPort)
|
||||
{
|
||||
this.stopPort = stopPort;
|
||||
}
|
||||
|
||||
public String getStopKey()
|
||||
{
|
||||
return stopKey;
|
||||
}
|
||||
|
||||
public void setStopKey(String stopKey)
|
||||
{
|
||||
this.stopKey = stopKey;
|
||||
}
|
||||
|
||||
public void setWebAppProperties(Properties props)
|
||||
{
|
||||
if (webAppProperties != null)
|
||||
webAppProperties.clear();
|
||||
|
||||
if (props != null)
|
||||
{
|
||||
if (webAppProperties == null)
|
||||
webAppProperties = new Properties();
|
||||
|
||||
webAppProperties.putAll(props);
|
||||
}
|
||||
}
|
||||
|
||||
public String getContextXml()
|
||||
{
|
||||
return contextXml;
|
||||
}
|
||||
|
||||
public void setContextXml(String contextXml)
|
||||
{
|
||||
this.contextXml = contextXml;
|
||||
}
|
||||
|
||||
public void doStart() throws Exception
|
||||
{
|
||||
super.doStart();
|
||||
|
||||
configure();
|
||||
configureShutdownMonitor();
|
||||
server.start();
|
||||
}
|
||||
|
||||
protected abstract void redeployWebApp() throws Exception;
|
||||
|
||||
public void redeployWebApp(Properties webaAppProperties) throws Exception
|
||||
{
|
||||
setWebAppProperties(webaAppProperties);
|
||||
redeployWebApp();
|
||||
}
|
||||
|
||||
public abstract void stopWebApp() throws Exception;
|
||||
|
||||
public void join() throws InterruptedException
|
||||
{
|
||||
server.join();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the server and the webapp
|
||||
* @throws Exception if there is an unspecified problem
|
||||
*/
|
||||
protected void configure() throws Exception
|
||||
{
|
||||
configureServer();
|
||||
configureWebApp();
|
||||
addWebAppToServer();
|
||||
}
|
||||
|
||||
protected void configureServer() throws Exception
|
||||
{
|
||||
//apply any configs from jetty.xml files first
|
||||
Server tmp = ServerSupport.applyXmlConfigurations(new Server(), jettyXmlFiles, jettyProperties);
|
||||
|
||||
if (tmp != null)
|
||||
server = tmp;
|
||||
|
||||
server.setStopAtShutdown(stopAtShutdown);
|
||||
|
||||
//ensure there's a connector
|
||||
if (httpConnector != null)
|
||||
httpConnector.setServer(server);
|
||||
|
||||
ServerSupport.configureConnectors(server, httpConnector, jettyProperties);
|
||||
|
||||
//set up handler structure
|
||||
ServerSupport.configureHandlers(server, contextHandlers, requestLog);
|
||||
|
||||
// set up security realms
|
||||
ServerSupport.configureLoginServices(server, loginServices);
|
||||
}
|
||||
|
||||
protected abstract void configureWebApp() throws Exception;
|
||||
|
||||
protected abstract void addWebAppToServer() throws Exception;
|
||||
|
||||
protected void applyWebAppProperties() throws Exception
|
||||
{
|
||||
//apply properties to the webapp if there are any
|
||||
if (contextXml != null)
|
||||
{
|
||||
if (webAppProperties == null)
|
||||
webAppProperties = new Properties();
|
||||
|
||||
webAppProperties.put("context.xml", contextXml);
|
||||
}
|
||||
}
|
||||
|
||||
private void configureShutdownMonitor()
|
||||
{
|
||||
if (stopPort > 0 && stopKey != null)
|
||||
{
|
||||
ShutdownMonitor monitor = ShutdownMonitor.getInstance();
|
||||
monitor.setPort(stopPort);
|
||||
monitor.setKey(stopKey);
|
||||
monitor.setExitVm(exitVm);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,276 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
||||
/**
|
||||
* AbstractServerForker
|
||||
*
|
||||
* Fork a jetty Server
|
||||
*/
|
||||
public abstract class AbstractServerForker extends AbstractForker
|
||||
{
|
||||
protected File forkWebXml;
|
||||
protected Server server;
|
||||
protected String containerClassPath;
|
||||
protected File webAppPropsFile;
|
||||
protected String contextXml;
|
||||
protected int scanInterval;
|
||||
protected String executionClassName;
|
||||
|
||||
/**
|
||||
* @return the scan
|
||||
*/
|
||||
public boolean isScan()
|
||||
{
|
||||
return scanInterval > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if true, the forked child will scan for changes at 1 second intervals.
|
||||
* @param scan if true, the forked child will scan for changes at 1 second intervals
|
||||
*/
|
||||
public void setScan(boolean scan)
|
||||
{
|
||||
setScanInterval(scan ? 1 : 0);
|
||||
}
|
||||
|
||||
public int getScanInterval()
|
||||
{
|
||||
return scanInterval;
|
||||
}
|
||||
|
||||
public void setScanInterval(int sec)
|
||||
{
|
||||
scanInterval = sec;
|
||||
}
|
||||
|
||||
public File getWebAppPropsFile()
|
||||
{
|
||||
return webAppPropsFile;
|
||||
}
|
||||
|
||||
public void setWebAppPropsFile(File webAppPropsFile)
|
||||
{
|
||||
this.webAppPropsFile = webAppPropsFile;
|
||||
}
|
||||
|
||||
public File getForkWebXml()
|
||||
{
|
||||
return forkWebXml;
|
||||
}
|
||||
|
||||
public void setForkWebXml(File forkWebXml)
|
||||
{
|
||||
this.forkWebXml = forkWebXml;
|
||||
}
|
||||
|
||||
public String getContextXml()
|
||||
{
|
||||
return contextXml;
|
||||
}
|
||||
|
||||
public void setContextXml(String contextXml)
|
||||
{
|
||||
this.contextXml = contextXml;
|
||||
}
|
||||
|
||||
public String getContainerClassPath()
|
||||
{
|
||||
return containerClassPath;
|
||||
}
|
||||
|
||||
public void setContainerClassPath(String containerClassPath)
|
||||
{
|
||||
this.containerClassPath = containerClassPath;
|
||||
}
|
||||
|
||||
public Server getServer()
|
||||
{
|
||||
return server;
|
||||
}
|
||||
|
||||
public void setServer(Server server)
|
||||
{
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doStart()
|
||||
throws Exception
|
||||
{
|
||||
generateWebApp();
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
protected abstract void generateWebApp() throws Exception;
|
||||
|
||||
protected abstract void redeployWebApp() throws Exception;
|
||||
|
||||
public ProcessBuilder createCommand()
|
||||
{
|
||||
List<String> cmd = new ArrayList<String>();
|
||||
cmd.add(getJavaBin());
|
||||
|
||||
if (jvmArgs != null)
|
||||
{
|
||||
String[] args = jvmArgs.split(" ");
|
||||
for (int i = 0; args != null && i < args.length; i++)
|
||||
{
|
||||
if (args[i] != null && !"".equals(args[i]))
|
||||
cmd.add(args[i].trim());
|
||||
}
|
||||
}
|
||||
|
||||
if (systemProperties != null)
|
||||
{
|
||||
for (Map.Entry<String, String> e:systemProperties.entrySet())
|
||||
{
|
||||
cmd.add("-D" + e.getKey() + "=" + e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (containerClassPath != null && containerClassPath.length() > 0)
|
||||
{
|
||||
cmd.add("-cp");
|
||||
cmd.add(containerClassPath);
|
||||
}
|
||||
|
||||
cmd.add(executionClassName);
|
||||
|
||||
if (stopPort > 0 && stopKey != null)
|
||||
{
|
||||
cmd.add("--stop-port");
|
||||
cmd.add(Integer.toString(stopPort));
|
||||
cmd.add("--stop-key");
|
||||
cmd.add(stopKey);
|
||||
}
|
||||
if (jettyXmlFiles != null)
|
||||
{
|
||||
cmd.add("--jetty-xml");
|
||||
StringBuilder tmp = new StringBuilder();
|
||||
for (File jettyXml:jettyXmlFiles)
|
||||
{
|
||||
if (tmp.length() != 0)
|
||||
tmp.append(",");
|
||||
tmp.append(jettyXml.getAbsolutePath());
|
||||
}
|
||||
cmd.add(tmp.toString());
|
||||
}
|
||||
|
||||
cmd.add("--webprops");
|
||||
cmd.add(webAppPropsFile.getAbsolutePath());
|
||||
|
||||
cmd.add("--token");
|
||||
cmd.add(tokenFile.getAbsolutePath());
|
||||
|
||||
if (scanInterval > 0)
|
||||
{
|
||||
cmd.add("--scanInterval");
|
||||
cmd.add(Integer.toString(scanInterval));
|
||||
}
|
||||
|
||||
if (jettyProperties != null)
|
||||
{
|
||||
for (Map.Entry<String, String> e:jettyProperties.entrySet())
|
||||
{
|
||||
cmd.add(e.getKey() + "=" + e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
ProcessBuilder command = new ProcessBuilder(cmd);
|
||||
command.directory(workDir);
|
||||
|
||||
if (PluginLog.getLog().isDebugEnabled())
|
||||
PluginLog.getLog().debug("Forked cli:" + command.command());
|
||||
|
||||
PluginLog.getLog().info("Forked process starting");
|
||||
|
||||
//set up extra environment vars if there are any
|
||||
if (env != null && !env.isEmpty())
|
||||
command.environment().putAll(env);
|
||||
|
||||
if (waitForChild)
|
||||
{
|
||||
command.inheritIO();
|
||||
}
|
||||
else
|
||||
{
|
||||
command.redirectOutput(jettyOutputFile);
|
||||
command.redirectErrorStream(true);
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the location of the java binary.
|
||||
* @return the location of the java binary
|
||||
*/
|
||||
private String getJavaBin()
|
||||
{
|
||||
String[] javaexes = new String[]{"java", "java.exe"};
|
||||
|
||||
File javaHomeDir = new File(System.getProperty("java.home"));
|
||||
for (String javaexe : javaexes)
|
||||
{
|
||||
File javabin = new File(javaHomeDir, fileSeparators("bin/" + javaexe));
|
||||
if (javabin.exists() && javabin.isFile())
|
||||
{
|
||||
return javabin.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
return "java";
|
||||
}
|
||||
|
||||
public static String fileSeparators(String path)
|
||||
{
|
||||
StringBuilder ret = new StringBuilder();
|
||||
for (char c : path.toCharArray())
|
||||
{
|
||||
if ((c == '/') || (c == '\\'))
|
||||
{
|
||||
ret.append(File.separatorChar);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.append(c);
|
||||
}
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
public static String pathSeparators(String path)
|
||||
{
|
||||
StringBuilder ret = new StringBuilder();
|
||||
for (char c : path.toCharArray())
|
||||
{
|
||||
if ((c == ',') || (c == ':'))
|
||||
{
|
||||
ret.append(File.pathSeparatorChar);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.append(c);
|
||||
}
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import java.io.Console;
|
||||
import java.util.EventListener;
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin.utils;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
@ -35,8 +35,6 @@ import org.eclipse.aether.artifact.DefaultArtifact;
|
|||
import org.eclipse.aether.resolution.ArtifactRequest;
|
||||
import org.eclipse.aether.resolution.ArtifactResolutionException;
|
||||
import org.eclipse.aether.resolution.ArtifactResult;
|
||||
import org.eclipse.jetty.ee9.maven.plugin.OverlayManager;
|
||||
import org.eclipse.jetty.ee9.maven.plugin.WarPluginInfo;
|
||||
|
||||
/**
|
||||
* MavenProjectHelper
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -24,7 +24,7 @@ import java.util.Objects;
|
|||
import java.util.Set;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.eclipse.jetty.ee9.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.MountedPathResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
@ -45,41 +45,41 @@ public class OverlayManager
|
|||
this.warPlugin = warPlugin;
|
||||
}
|
||||
|
||||
public void applyOverlays(MavenWebAppContext webApp)
|
||||
public void applyOverlays(ContextHandler contextHandler, boolean append)
|
||||
throws Exception
|
||||
{
|
||||
List<Resource> resourceBases = new ArrayList<Resource>();
|
||||
|
||||
for (Overlay o : getOverlays(webApp))
|
||||
for (Overlay o : getOverlays(contextHandler))
|
||||
{
|
||||
//can refer to the current project in list of overlays for ordering purposes
|
||||
if (o.getConfig() != null && o.getConfig().isCurrentProject() && webApp.getBaseResource().exists())
|
||||
if (o.getConfig() != null && o.getConfig().isCurrentProject() && contextHandler.getBaseResource().exists())
|
||||
{
|
||||
resourceBases.add(webApp.getBaseResource());
|
||||
resourceBases.add(contextHandler.getBaseResource());
|
||||
continue;
|
||||
}
|
||||
//add in the selectively unpacked overlay in the correct order to the webapp's resource base
|
||||
resourceBases.add(unpackOverlay(webApp, o));
|
||||
resourceBases.add(unpackOverlay(contextHandler, o));
|
||||
}
|
||||
|
||||
if (!resourceBases.contains(webApp.getBaseResource()) && webApp.getBaseResource().exists())
|
||||
if (!resourceBases.contains(contextHandler.getBaseResource()) && contextHandler.getBaseResource().exists())
|
||||
{
|
||||
if (webApp.getBaseAppFirst())
|
||||
resourceBases.add(0, webApp.getBaseResource());
|
||||
if (append)
|
||||
resourceBases.add(0, contextHandler.getBaseResource());
|
||||
else
|
||||
resourceBases.add(webApp.getBaseResource());
|
||||
resourceBases.add(contextHandler.getBaseResource());
|
||||
}
|
||||
|
||||
webApp.setBaseResource(ResourceFactory.combine(resourceBases));
|
||||
contextHandler.setBaseResource(ResourceFactory.combine(resourceBases));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an ordered list of overlays
|
||||
*/
|
||||
protected List<Overlay> getOverlays(WebAppContext webApp)
|
||||
private List<Overlay> getOverlays(ContextHandler contextHandler)
|
||||
throws Exception
|
||||
{
|
||||
Objects.requireNonNull(webApp);
|
||||
Objects.requireNonNull(contextHandler);
|
||||
|
||||
Set<Artifact> matchedWarArtifacts = new HashSet<Artifact>();
|
||||
List<Overlay> overlays = new ArrayList<Overlay>();
|
||||
|
@ -104,7 +104,7 @@ public class OverlayManager
|
|||
if (a != null)
|
||||
{
|
||||
matchedWarArtifacts.add(a);
|
||||
Resource resource = webApp.getResourceFactory().newJarFileResource(a.getFile().toPath().toUri());
|
||||
Resource resource = ResourceFactory.of(contextHandler).newJarFileResource(a.getFile().toPath().toUri());
|
||||
SelectiveJarResource r = new SelectiveJarResource(resource);
|
||||
r.setIncludes(config.getIncludes());
|
||||
r.setExcludes(config.getExcludes());
|
||||
|
@ -118,7 +118,7 @@ public class OverlayManager
|
|||
{
|
||||
if (!matchedWarArtifacts.contains(a))
|
||||
{
|
||||
Resource resource = webApp.getResourceFactory().newJarFileResource(a.getFile().toPath().toUri());
|
||||
Resource resource = ResourceFactory.of(contextHandler).newJarFileResource(a.getFile().toPath().toUri());
|
||||
Overlay overlay = new Overlay(null, resource);
|
||||
overlays.add(overlay);
|
||||
}
|
||||
|
@ -133,10 +133,10 @@ public class OverlayManager
|
|||
* @return the location to which it was unpacked
|
||||
* @throws IOException if there is an IO problem
|
||||
*/
|
||||
protected Resource unpackOverlay(WebAppContext webApp, Overlay overlay)
|
||||
protected Resource unpackOverlay(ContextHandler contextHandler, Overlay overlay)
|
||||
throws IOException
|
||||
{
|
||||
Objects.requireNonNull(webApp);
|
||||
Objects.requireNonNull(contextHandler);
|
||||
Objects.requireNonNull(overlay);
|
||||
|
||||
if (overlay.getResource() == null)
|
||||
|
@ -161,6 +161,6 @@ public class OverlayManager
|
|||
overlay.unpackTo(unpackDir);
|
||||
|
||||
//use top level of unpacked content
|
||||
return webApp.getResourceFactory().newResource(unpackDir.getCanonicalPath());
|
||||
return ResourceFactory.of(contextHandler).newResource(unpackDir.getCanonicalPath());
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.nio.file.AtomicMoveNotSupportedException;
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Enumeration;
|
||||
|
@ -19,8 +19,8 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.ee9.webapp.Configurations;
|
||||
import org.eclipse.jetty.ee9.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.maven.MavenServerConnector;
|
||||
import org.eclipse.jetty.maven.PluginLog;
|
||||
import org.eclipse.jetty.security.LoginService;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
|
@ -37,12 +37,6 @@ import org.eclipse.jetty.xml.XmlConfiguration;
|
|||
*/
|
||||
public class ServerSupport
|
||||
{
|
||||
|
||||
public static void configureDefaultConfigurationClasses(Server server)
|
||||
{
|
||||
Configurations.setServerDefault(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the handler structure to receive a webapp.
|
||||
* Also put in a DefaultHandler so we get a nicer page
|
||||
|
@ -144,7 +138,7 @@ public class ServerSupport
|
|||
* @param webapp the webapp to add
|
||||
* @throws Exception if there is an unspecified problem
|
||||
*/
|
||||
public static void addWebApplication(Server server, WebAppContext webapp) throws Exception
|
||||
public static void addWebApplication(Server server, ContextHandler webapp) throws Exception
|
||||
{
|
||||
if (server == null)
|
||||
throw new IllegalArgumentException("Server is null");
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee9.maven.plugin;
|
||||
package org.eclipse.jetty.maven;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
|
@ -1,8 +1,8 @@
|
|||
# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
|
||||
|
||||
[description]
|
||||
Enables the jetty-rewrite handler.
|
||||
Specific rewrite rules must be added to etc/jetty-rewrite-rules.xml.
|
||||
Adds the RewriteHandler to the Handler chain.
|
||||
Specific rewrite rules must be added to $JETTY_BASE/etc/jetty-rewrite-rules.xml.
|
||||
|
||||
[tags]
|
||||
server
|
||||
|
@ -24,5 +24,7 @@ etc/jetty-rewrite.xml
|
|||
etc/jetty-rewrite-rules.xml
|
||||
|
||||
[ini-template]
|
||||
# tag::documentation[]
|
||||
## Request attribute name used to store the original request path.
|
||||
# jetty.rewrite.originalPathAttribute=jetty.rewrite.originalRequestPath
|
||||
# end::documentation[]
|
||||
|
|
|
@ -66,7 +66,7 @@ public class HeaderRegexRule extends RegexRule
|
|||
}
|
||||
|
||||
/**
|
||||
* Set true to add the response header, false to put the response header..
|
||||
* Set true to add the response header, false to put the response header.
|
||||
* @param add true to add the response header, false to put the response header.
|
||||
*/
|
||||
public void setAdd(boolean add)
|
||||
|
|
|
@ -53,7 +53,7 @@ public class RedirectPatternRule extends PatternRule
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the location to redirect..
|
||||
* Set the location to redirect.
|
||||
* @param value the location to redirect.
|
||||
*/
|
||||
public void setLocation(String value)
|
||||
|
|
|
@ -55,7 +55,7 @@ public class RedirectRegexRule extends RegexRule
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the location to redirect..
|
||||
* Set the location to redirect.
|
||||
* @param location the location to redirect.
|
||||
*/
|
||||
public void setLocation(String location)
|
||||
|
|
|
@ -43,7 +43,7 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
/**
|
||||
* Customize Requests for Proxy Forwarding.
|
||||
* <p>
|
||||
* This customizer looks at at HTTP request for headers that indicate
|
||||
* This customizer looks at HTTP request for headers that indicate
|
||||
* it has been forwarded by one or more proxies. Specifically handled are
|
||||
* <ul>
|
||||
* <li>{@code Forwarded}, as defined by <a href="https://tools.ietf.org/html/rfc7239">rfc7239</a>
|
||||
|
@ -80,7 +80,7 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* <tbody style="text-align: left; vertical-align: top;">
|
||||
* <tr>
|
||||
* <td>1</td>
|
||||
* <td><code>Forwarded</code> Header</td>
|
||||
* <td>{@code Forwarded} Header</td>
|
||||
* <td>"{@code host=<host>}" param (Required)</td>
|
||||
* <td>"{@code host=<host>:<port>} param (Implied)</td>
|
||||
* <td>"{@code proto=<value>}" param (Optional)</td>
|
||||
|
@ -88,7 +88,7 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* </tr>
|
||||
* <tr>
|
||||
* <td>2</td>
|
||||
* <td><code>X-Forwarded-Host</code> Header</td>
|
||||
* <td>{@code X-Forwarded-Host} Header</td>
|
||||
* <td>Required</td>
|
||||
* <td>Implied</td>
|
||||
* <td>n/a</td>
|
||||
|
@ -96,7 +96,7 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* </tr>
|
||||
* <tr>
|
||||
* <td>3</td>
|
||||
* <td><code>X-Forwarded-Port</code> Header</td>
|
||||
* <td>{@code X-Forwarded-Port} Header</td>
|
||||
* <td>n/a</td>
|
||||
* <td>Required</td>
|
||||
* <td>n/a</td>
|
||||
|
@ -104,7 +104,7 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* </tr>
|
||||
* <tr>
|
||||
* <td>4</td>
|
||||
* <td><code>X-Forwarded-Server</code> Header</td>
|
||||
* <td>{@code X-Forwarded-Server} Header</td>
|
||||
* <td>Required</td>
|
||||
* <td>Optional</td>
|
||||
* <td>n/a</td>
|
||||
|
@ -112,29 +112,29 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* </tr>
|
||||
* <tr>
|
||||
* <td>5</td>
|
||||
* <td><code>X-Forwarded-Proto</code> Header</td>
|
||||
* <td>{@code X-Forwarded-Proto} Header</td>
|
||||
* <td>n/a</td>
|
||||
* <td>Implied from value</td>
|
||||
* <td>Required</td>
|
||||
* <td>
|
||||
* <p>left-most value becomes protocol.</p>
|
||||
* <ul>
|
||||
* <li>Value of "<code>http</code>" means port=80.</li>
|
||||
* <li>Value of "{@code http}" means port=80.</li>
|
||||
* <li>Value of "{@link HttpConfiguration#getSecureScheme()}" means port={@link HttpConfiguration#getSecurePort()}.</li>
|
||||
* </ul>
|
||||
* </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>6</td>
|
||||
* <td><code>X-Proxied-Https</code> Header</td>
|
||||
* <td>{@code X-Proxied-Https} Header</td>
|
||||
* <td>n/a</td>
|
||||
* <td>Implied from value</td>
|
||||
* <td>boolean</td>
|
||||
* <td>
|
||||
* <p>left-most value determines protocol and port.</p>
|
||||
* <ul>
|
||||
* <li>Value of "<code>on</code>" means port={@link HttpConfiguration#getSecurePort()}, and protocol={@link HttpConfiguration#getSecureScheme()}).</li>
|
||||
* <li>Value of "<code>off</code>" means port=80, and protocol=http.</li>
|
||||
* <li>Value of "{@code on}" means port={@link HttpConfiguration#getSecurePort()}, and protocol={@link HttpConfiguration#getSecureScheme()}).</li>
|
||||
* <li>Value of "{@code off}" means port=80, and protocol=http.</li>
|
||||
* </ul>
|
||||
* </td>
|
||||
* </tr>
|
||||
|
@ -799,12 +799,7 @@ public class ForwardedRequestCustomizer implements HttpConfiguration.Customizer
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
final StringBuilder sb = new StringBuilder("MutableHostPort{");
|
||||
sb.append("host='").append(_host).append("'/").append(_hostSource);
|
||||
sb.append(", port=").append(_port);
|
||||
sb.append("/").append(_portSource);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
return "%s@%x{host='%s'/%s, port=%d/%s}".formatted(getClass().getSimpleName(), hashCode(), _host, _hostSource, _port, _portSource);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -888,7 +883,7 @@ public class ForwardedRequestCustomizer implements HttpConfiguration.Customizer
|
|||
}
|
||||
|
||||
/**
|
||||
* Called if header is <code>Proxy-auth-cert</code>
|
||||
* Called if header is {@code Proxy-auth-cert}
|
||||
*/
|
||||
public void handleCipherSuite(HttpField field)
|
||||
{
|
||||
|
@ -904,7 +899,7 @@ public class ForwardedRequestCustomizer implements HttpConfiguration.Customizer
|
|||
}
|
||||
|
||||
/**
|
||||
* Called if header is <code>Proxy-Ssl-Id</code>
|
||||
* Called if header is {@code Proxy-Ssl-Id}
|
||||
*/
|
||||
public void handleSslSessionId(HttpField field)
|
||||
{
|
||||
|
@ -920,7 +915,7 @@ public class ForwardedRequestCustomizer implements HttpConfiguration.Customizer
|
|||
}
|
||||
|
||||
/**
|
||||
* Called if header is <code>X-Forwarded-Host</code>
|
||||
* Called if header is {@code X-Forwarded-Host}
|
||||
*/
|
||||
public void handleForwardedHost(HttpField field)
|
||||
{
|
||||
|
@ -928,7 +923,7 @@ public class ForwardedRequestCustomizer implements HttpConfiguration.Customizer
|
|||
}
|
||||
|
||||
/**
|
||||
* Called if header is <code>X-Forwarded-For</code>
|
||||
* Called if header is {@code X-Forwarded-For}
|
||||
*/
|
||||
public void handleForwardedFor(HttpField field)
|
||||
{
|
||||
|
@ -937,7 +932,7 @@ public class ForwardedRequestCustomizer implements HttpConfiguration.Customizer
|
|||
}
|
||||
|
||||
/**
|
||||
* Called if header is <code>X-Forwarded-Server</code>
|
||||
* Called if header is {@code X-Forwarded-Server}
|
||||
*/
|
||||
public void handleForwardedServer(HttpField field)
|
||||
{
|
||||
|
@ -947,7 +942,7 @@ public class ForwardedRequestCustomizer implements HttpConfiguration.Customizer
|
|||
}
|
||||
|
||||
/**
|
||||
* Called if header is <code>X-Forwarded-Port</code>
|
||||
* Called if header is {@code X-Forwarded-Port}
|
||||
*/
|
||||
public void handleForwardedPort(HttpField field)
|
||||
{
|
||||
|
@ -957,7 +952,7 @@ public class ForwardedRequestCustomizer implements HttpConfiguration.Customizer
|
|||
}
|
||||
|
||||
/**
|
||||
* Called if header is <code>X-Forwarded-Proto</code>
|
||||
* Called if header is {@code X-Forwarded-Proto}
|
||||
*/
|
||||
public void handleProto(HttpField field)
|
||||
{
|
||||
|
@ -965,7 +960,7 @@ public class ForwardedRequestCustomizer implements HttpConfiguration.Customizer
|
|||
}
|
||||
|
||||
/**
|
||||
* Called if header is <code>X-Proxied-Https</code>
|
||||
* Called if header is {@code X-Proxied-Https}
|
||||
*/
|
||||
public void handleHttps(HttpField field)
|
||||
{
|
||||
|
@ -988,7 +983,7 @@ public class ForwardedRequestCustomizer implements HttpConfiguration.Customizer
|
|||
}
|
||||
|
||||
/**
|
||||
* Called if header is <code>Forwarded</code>
|
||||
* Called if header is {@code Forwarded}
|
||||
*/
|
||||
public void handleRFC7239(HttpField field)
|
||||
{
|
||||
|
|
|
@ -67,7 +67,7 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
|||
/**
|
||||
* @param sniHostCheck True if the SNI Host name must match.
|
||||
* @param stsMaxAgeSeconds The max age in seconds for a Strict-Transport-Security response header. If set less than zero then no header is sent.
|
||||
* @param stsIncludeSubdomains If true, a include subdomain property is sent with any Strict-Transport-Security header
|
||||
* @param stsIncludeSubdomains If true, an include subdomain property is sent with any Strict-Transport-Security header
|
||||
*/
|
||||
public SecureRequestCustomizer(
|
||||
@Name("sniHostCheck") boolean sniHostCheck,
|
||||
|
@ -81,7 +81,7 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
|||
* @param sniRequired True if a SNI certificate is required.
|
||||
* @param sniHostCheck True if the SNI Host name must match.
|
||||
* @param stsMaxAgeSeconds The max age in seconds for a Strict-Transport-Security response header. If set less than zero then no header is sent.
|
||||
* @param stsIncludeSubdomains If true, a include subdomain property is sent with any Strict-Transport-Security header
|
||||
* @param stsIncludeSubdomains If true, an include subdomain property is sent with any Strict-Transport-Security header
|
||||
*/
|
||||
public SecureRequestCustomizer(
|
||||
@Name("sniRequired") boolean sniRequired,
|
||||
|
|
|
@ -109,6 +109,7 @@ public class SizeLimitHandler extends Handler.Wrapper
|
|||
{
|
||||
private final HttpFields.Mutable _httpFields;
|
||||
private long _written = 0;
|
||||
private HttpException.RuntimeException _failure;
|
||||
|
||||
public SizeLimitResponseWrapper(Request request, Response wrapped)
|
||||
{
|
||||
|
@ -119,7 +120,7 @@ public class SizeLimitHandler extends Handler.Wrapper
|
|||
@Override
|
||||
public HttpField onAddField(HttpField field)
|
||||
{
|
||||
if (field.getHeader().is(HttpHeader.CONTENT_LENGTH.asString()))
|
||||
if (field.getHeader() == HttpHeader.CONTENT_LENGTH)
|
||||
{
|
||||
long contentLength = field.getLongValue();
|
||||
if (_responseLimit >= 0 && contentLength > _responseLimit)
|
||||
|
@ -139,12 +140,19 @@ public class SizeLimitHandler extends Handler.Wrapper
|
|||
@Override
|
||||
public void write(boolean last, ByteBuffer content, Callback callback)
|
||||
{
|
||||
if (_failure != null)
|
||||
{
|
||||
callback.failed(_failure);
|
||||
return;
|
||||
}
|
||||
|
||||
if (content != null && content.remaining() > 0)
|
||||
{
|
||||
if (_responseLimit >= 0 && (_written + content.remaining()) > _responseLimit)
|
||||
{
|
||||
String message = "Response body is too large: %d>%d".formatted(_written + content.remaining(), _responseLimit);
|
||||
callback.failed(new HttpException.RuntimeException(HttpStatus.INTERNAL_SERVER_ERROR_500, message));
|
||||
_failure = new HttpException.RuntimeException(HttpStatus.INTERNAL_SERVER_ERROR_500,
|
||||
"Response body is too large: %d>%d".formatted(_written + content.remaining(), _responseLimit));
|
||||
callback.failed(_failure);
|
||||
return;
|
||||
}
|
||||
_written += content.remaining();
|
||||
|
|
|
@ -16,6 +16,7 @@ package org.eclipse.jetty.server;
|
|||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -25,7 +26,10 @@ import org.eclipse.jetty.http.HttpCookie;
|
|||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.HttpTester;
|
||||
import org.eclipse.jetty.http.UriCompliance;
|
||||
import org.eclipse.jetty.io.Content;
|
||||
import org.eclipse.jetty.server.LocalConnector.LocalEndPoint;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.DumpHandler;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
|
@ -96,6 +100,49 @@ public class RequestTest
|
|||
assertEquals(HttpStatus.BAD_REQUEST_400, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAmbiguousPathSep() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
for (Connector connector: server.getConnectors())
|
||||
{
|
||||
HttpConnectionFactory httpConnectionFactory = connector.getConnectionFactory(HttpConnectionFactory.class);
|
||||
if (httpConnectionFactory != null)
|
||||
{
|
||||
HttpConfiguration httpConfiguration = httpConnectionFactory.getHttpConfiguration();
|
||||
httpConfiguration.setUriCompliance(UriCompliance.from(
|
||||
EnumSet.of(UriCompliance.Violation.AMBIGUOUS_PATH_SEPARATOR)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
ContextHandler fooContext = new ContextHandler();
|
||||
fooContext.setContextPath("/foo");
|
||||
fooContext.setHandler(new Handler.Abstract()
|
||||
{
|
||||
@Override
|
||||
public boolean handle(Request request, Response response, Callback callback)
|
||||
{
|
||||
String pathInContext = Request.getPathInContext(request);
|
||||
String msg = String.format("pathInContext=\"%s\"", pathInContext);
|
||||
response.getHeaders().put(HttpHeader.CONTENT_TYPE, "text/plain;charset=utf-8");
|
||||
Content.Sink.write(response, true, msg, callback);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
server.setHandler(fooContext);
|
||||
server.start();
|
||||
String request = """
|
||||
GET /foo/zed%2Fbar HTTP/1.1\r
|
||||
Host: local\r
|
||||
Connection: close\r
|
||||
\r
|
||||
""";
|
||||
HttpTester.Response response = HttpTester.parseResponse(connector.getResponse(request));
|
||||
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
assertThat(response.getContent(), is("pathInContext=\"/zed%2Fbar\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectRequestURLSameAsHost() throws Exception
|
||||
{
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
<module>jetty-jmx</module>
|
||||
<module>jetty-jndi</module>
|
||||
<module>jetty-keystore</module>
|
||||
<module>jetty-maven</module>
|
||||
<module>jetty-openid</module>
|
||||
<module>jetty-osgi</module>
|
||||
<module>jetty-plus</module>
|
||||
|
|
|
@ -81,6 +81,11 @@
|
|||
<artifactId>jetty-jndi</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-maven</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<Ref refid="httpConnector">
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -112,7 +112,7 @@
|
|||
</jettyXmls>
|
||||
<loginServices>
|
||||
<loginService implementation="org.eclipse.jetty.security.HashLoginService">
|
||||
<config implementation="org.eclipse.jetty.ee10.maven.plugin.MavenResource">
|
||||
<config implementation="org.eclipse.jetty.maven.MavenResource">
|
||||
<resourceAsString>${basedir}/src/config/login.xml</resourceAsString>
|
||||
</config>
|
||||
</loginService>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<Ref refid="httpConnector">
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -1,251 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* AbstractForker
|
||||
*
|
||||
* Base class for forking jetty.
|
||||
*/
|
||||
public abstract class AbstractForker extends AbstractLifeCycle
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractForker.class);
|
||||
|
||||
protected Map<String, String> env;
|
||||
|
||||
protected String jvmArgs;
|
||||
|
||||
protected boolean exitVm;
|
||||
|
||||
protected boolean stopAtShutdown;
|
||||
|
||||
protected List<File> jettyXmlFiles;
|
||||
|
||||
protected Map<String, String> jettyProperties;
|
||||
|
||||
protected int stopPort;
|
||||
|
||||
protected String stopKey;
|
||||
|
||||
protected File jettyOutputFile;
|
||||
|
||||
protected boolean waitForChild;
|
||||
|
||||
protected int maxChildStartChecks = 10; //check up to 10 times for child to start
|
||||
|
||||
protected long maxChildStartCheckMs = 200; //wait 200ms between checks
|
||||
|
||||
protected File tokenFile;
|
||||
|
||||
protected File workDir;
|
||||
|
||||
protected Map<String, String> systemProperties;
|
||||
|
||||
protected abstract ProcessBuilder createCommand();
|
||||
|
||||
protected abstract void redeployWebApp() throws Exception;
|
||||
|
||||
public File getWorkDir()
|
||||
{
|
||||
return workDir;
|
||||
}
|
||||
|
||||
public void setWorkDir(File workDir)
|
||||
{
|
||||
this.workDir = workDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the systemProperties
|
||||
*/
|
||||
public Map<String, String> getSystemProperties()
|
||||
{
|
||||
return systemProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the systemProperties to set.
|
||||
* @param systemProperties the systemProperties to set
|
||||
*/
|
||||
public void setSystemProperties(Map<String, String> systemProperties)
|
||||
{
|
||||
this.systemProperties = systemProperties;
|
||||
}
|
||||
|
||||
public Map<String, String> getEnv()
|
||||
{
|
||||
return env;
|
||||
}
|
||||
|
||||
public void setEnv(Map<String, String> env)
|
||||
{
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public String getJvmArgs()
|
||||
{
|
||||
return jvmArgs;
|
||||
}
|
||||
|
||||
public void setJvmArgs(String jvmArgs)
|
||||
{
|
||||
this.jvmArgs = jvmArgs;
|
||||
}
|
||||
|
||||
public boolean isExitVm()
|
||||
{
|
||||
return exitVm;
|
||||
}
|
||||
|
||||
public void setExitVm(boolean exitVm)
|
||||
{
|
||||
this.exitVm = exitVm;
|
||||
}
|
||||
|
||||
public boolean isStopAtShutdown()
|
||||
{
|
||||
return stopAtShutdown;
|
||||
}
|
||||
|
||||
public void setStopAtShutdown(boolean stopAtShutdown)
|
||||
{
|
||||
this.stopAtShutdown = stopAtShutdown;
|
||||
}
|
||||
|
||||
public List<File> getJettyXmlFiles()
|
||||
{
|
||||
return jettyXmlFiles;
|
||||
}
|
||||
|
||||
public void setJettyXmlFiles(List<File> jettyXmlFiles)
|
||||
{
|
||||
this.jettyXmlFiles = jettyXmlFiles;
|
||||
}
|
||||
|
||||
public Map<String, String> getJettyProperties()
|
||||
{
|
||||
return jettyProperties;
|
||||
}
|
||||
|
||||
public void setJettyProperties(Map<String, String> jettyProperties)
|
||||
{
|
||||
this.jettyProperties = jettyProperties;
|
||||
}
|
||||
|
||||
public int getStopPort()
|
||||
{
|
||||
return stopPort;
|
||||
}
|
||||
|
||||
public void setStopPort(int stopPort)
|
||||
{
|
||||
this.stopPort = stopPort;
|
||||
}
|
||||
|
||||
public String getStopKey()
|
||||
{
|
||||
return stopKey;
|
||||
}
|
||||
|
||||
public void setStopKey(String stopKey)
|
||||
{
|
||||
this.stopKey = stopKey;
|
||||
}
|
||||
|
||||
public File getJettyOutputFile()
|
||||
{
|
||||
return jettyOutputFile;
|
||||
}
|
||||
|
||||
public void setJettyOutputFile(File jettyOutputFile)
|
||||
{
|
||||
this.jettyOutputFile = jettyOutputFile;
|
||||
}
|
||||
|
||||
public boolean isWaitForChild()
|
||||
{
|
||||
return waitForChild;
|
||||
}
|
||||
|
||||
public void setWaitForChild(boolean waitForChild)
|
||||
{
|
||||
this.waitForChild = waitForChild;
|
||||
}
|
||||
|
||||
public int getMaxChildtartChecks()
|
||||
{
|
||||
return maxChildStartChecks;
|
||||
}
|
||||
|
||||
public void setMaxChildStartChecks(int maxChildStartChecks)
|
||||
{
|
||||
this.maxChildStartChecks = maxChildStartChecks;
|
||||
}
|
||||
|
||||
public long getMaxChildStartCheckMs()
|
||||
{
|
||||
return maxChildStartCheckMs;
|
||||
}
|
||||
|
||||
public void setMaxChildStartCheckMs(long maxChildStartCheckMs)
|
||||
{
|
||||
this.maxChildStartCheckMs = maxChildStartCheckMs;
|
||||
}
|
||||
|
||||
public File getTokenFile()
|
||||
{
|
||||
return tokenFile;
|
||||
}
|
||||
|
||||
public void setTokenFile(File tokenFile)
|
||||
{
|
||||
this.tokenFile = tokenFile;
|
||||
}
|
||||
|
||||
public void doStart()
|
||||
throws Exception
|
||||
{
|
||||
super.doStart();
|
||||
|
||||
//Create the command to fork
|
||||
ProcessBuilder command = createCommand();
|
||||
Process process = command.start();
|
||||
|
||||
if (waitForChild)
|
||||
{
|
||||
//keep executing until the child dies
|
||||
process.waitFor();
|
||||
}
|
||||
else
|
||||
{
|
||||
//just wait until the child has started successfully
|
||||
int attempts = maxChildStartChecks;
|
||||
while (!tokenFile.exists() && attempts > 0)
|
||||
{
|
||||
Thread.sleep(maxChildStartCheckMs);
|
||||
--attempts;
|
||||
}
|
||||
if (attempts <= 0)
|
||||
LOG.info("Couldn't verify success of child startup");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ import org.apache.maven.artifact.Artifact;
|
|||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.eclipse.jetty.maven.ScanPattern;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.Resources;
|
||||
|
||||
|
@ -123,7 +124,7 @@ public abstract class AbstractUnassembledWebAppMojo extends AbstractWebAppMojo
|
|||
*
|
||||
* @throws IOException if there is an IO problem
|
||||
*/
|
||||
protected void configureUnassembledWebApp() throws IOException
|
||||
protected void configureUnassembledWebApp() throws Exception
|
||||
{
|
||||
//Set up the location of the webapp.
|
||||
//There are 2 parts to this: setWar() and setBaseResource(). On standalone jetty,
|
||||
|
@ -208,7 +209,7 @@ public abstract class AbstractUnassembledWebAppMojo extends AbstractWebAppMojo
|
|||
|
||||
//process any overlays and the war type artifacts, and
|
||||
//sets up the base resource collection for the webapp
|
||||
mavenProjectHelper.getOverlayManager().applyOverlays(webApp);
|
||||
mavenProjectHelper.getOverlayManager().applyOverlays(webApp, webApp.getBaseAppFirst());
|
||||
|
||||
getLog().info("web.xml file = " + webApp.getDescriptor());
|
||||
getLog().info("Webapp directory = " + webAppSourceDirectory.getCanonicalPath());
|
||||
|
|
|
@ -48,7 +48,10 @@ import org.apache.maven.plugins.annotations.Parameter;
|
|||
import org.apache.maven.project.MavenProject;
|
||||
import org.codehaus.plexus.util.StringUtils;
|
||||
import org.eclipse.aether.RepositorySystem;
|
||||
import org.eclipse.jetty.ee10.maven.plugin.utils.MavenProjectHelper;
|
||||
import org.eclipse.jetty.maven.MavenProjectHelper;
|
||||
import org.eclipse.jetty.maven.MavenServerConnector;
|
||||
import org.eclipse.jetty.maven.PluginLog;
|
||||
import org.eclipse.jetty.maven.ScanTargetPattern;
|
||||
import org.eclipse.jetty.security.LoginService;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
@ -563,7 +566,7 @@ public abstract class AbstractWebAppMojo extends AbstractMojo
|
|||
if (jettyHome == null)
|
||||
jetty.setJettyHomeZip(jettyHomeZip != null ? jettyHomeZip : mavenProjectHelper.resolveArtifact(JETTY_HOME_GROUPID, JETTY_HOME_ARTIFACTID, plugin.getVersion(), "zip"));
|
||||
|
||||
jetty.version = plugin.getVersion();
|
||||
jetty.setVersion(plugin.getVersion());
|
||||
jetty.setJettyHome(jettyHome);
|
||||
jetty.setJettyBase(jettyBase);
|
||||
jetty.setBaseDir(target);
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin;
|
||||
|
||||
import java.io.Console;
|
||||
import java.util.EventListener;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* ConsoleReader
|
||||
*
|
||||
* Reads lines from the System console and supplies them
|
||||
* to ConsoleReader.Listeners.
|
||||
*/
|
||||
public class ConsoleReader implements Runnable
|
||||
{
|
||||
public interface Listener extends EventListener
|
||||
{
|
||||
public void consoleEvent(String line);
|
||||
}
|
||||
|
||||
public Set<ConsoleReader.Listener> listeners = new HashSet<>();
|
||||
|
||||
public void addListener(ConsoleReader.Listener listener)
|
||||
{
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeListener(ConsoleReader.Listener listener)
|
||||
{
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
Console console = System.console();
|
||||
if (console == null)
|
||||
return;
|
||||
|
||||
String line = "";
|
||||
while (true && line != null)
|
||||
{
|
||||
line = console.readLine("%nHit <enter> to redeploy:%n%n");
|
||||
if (line != null)
|
||||
signalEvent(line);
|
||||
}
|
||||
}
|
||||
|
||||
private void signalEvent(String line)
|
||||
{
|
||||
for (ConsoleReader.Listener l:listeners)
|
||||
l.consoleEvent(line);
|
||||
}
|
||||
}
|
|
@ -13,220 +13,40 @@
|
|||
|
||||
package org.eclipse.jetty.ee10.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.eclipse.jetty.ee10.quickstart.QuickStartConfiguration;
|
||||
import org.eclipse.jetty.ee10.quickstart.QuickStartConfiguration.Mode;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.security.LoginService;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ShutdownMonitor;
|
||||
import org.eclipse.jetty.ee10.webapp.Configurations;
|
||||
import org.eclipse.jetty.maven.AbstractJettyEmbedder;
|
||||
import org.eclipse.jetty.maven.ServerSupport;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
|
||||
/**
|
||||
* JettyEmbedded
|
||||
* JettyEmbedder
|
||||
*
|
||||
* Starts jetty within the current process.
|
||||
*/
|
||||
public class JettyEmbedder extends AbstractLifeCycle
|
||||
public class JettyEmbedder extends AbstractJettyEmbedder
|
||||
{
|
||||
protected List<ContextHandler> contextHandlers;
|
||||
protected List<LoginService> loginServices;
|
||||
protected RequestLog requestLog;
|
||||
protected MavenServerConnector httpConnector;
|
||||
protected Server server;
|
||||
protected MavenWebAppContext webApp;
|
||||
protected boolean exitVm;
|
||||
protected boolean stopAtShutdown;
|
||||
protected List<File> jettyXmlFiles;
|
||||
protected Map<String, String> jettyProperties;
|
||||
protected ShutdownMonitor shutdownMonitor;
|
||||
protected int stopPort;
|
||||
protected String stopKey;
|
||||
private String contextXml;
|
||||
private Properties webAppProperties;
|
||||
|
||||
public List<ContextHandler> getContextHandlers()
|
||||
{
|
||||
return contextHandlers;
|
||||
}
|
||||
|
||||
public void setContextHandlers(List<ContextHandler> contextHandlers)
|
||||
{
|
||||
if (contextHandlers == null)
|
||||
this.contextHandlers = null;
|
||||
else
|
||||
this.contextHandlers = new ArrayList<>(contextHandlers);
|
||||
}
|
||||
|
||||
public List<LoginService> getLoginServices()
|
||||
{
|
||||
return loginServices;
|
||||
}
|
||||
|
||||
public void setLoginServices(List<LoginService> loginServices)
|
||||
{
|
||||
if (loginServices == null)
|
||||
this.loginServices = null;
|
||||
else
|
||||
this.loginServices = new ArrayList<>(loginServices);
|
||||
}
|
||||
|
||||
public RequestLog getRequestLog()
|
||||
{
|
||||
return requestLog;
|
||||
}
|
||||
|
||||
public void setRequestLog(RequestLog requestLog)
|
||||
{
|
||||
this.requestLog = requestLog;
|
||||
}
|
||||
|
||||
public MavenServerConnector getHttpConnector()
|
||||
{
|
||||
return httpConnector;
|
||||
}
|
||||
|
||||
public void setHttpConnector(MavenServerConnector httpConnector)
|
||||
{
|
||||
this.httpConnector = httpConnector;
|
||||
}
|
||||
|
||||
public Server getServer()
|
||||
{
|
||||
return server;
|
||||
}
|
||||
|
||||
public void setServer(Server server)
|
||||
{
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public MavenWebAppContext getWebApp()
|
||||
{
|
||||
return webApp;
|
||||
}
|
||||
|
||||
public boolean isExitVm()
|
||||
{
|
||||
return exitVm;
|
||||
}
|
||||
|
||||
public void setExitVm(boolean exitVm)
|
||||
{
|
||||
this.exitVm = exitVm;
|
||||
}
|
||||
|
||||
public boolean isStopAtShutdown()
|
||||
{
|
||||
return stopAtShutdown;
|
||||
}
|
||||
|
||||
public void setStopAtShutdown(boolean stopAtShutdown)
|
||||
{
|
||||
this.stopAtShutdown = stopAtShutdown;
|
||||
}
|
||||
|
||||
public List<File> getJettyXmlFiles()
|
||||
{
|
||||
return jettyXmlFiles;
|
||||
}
|
||||
|
||||
public void setJettyXmlFiles(List<File> jettyXmlFiles)
|
||||
{
|
||||
this.jettyXmlFiles = jettyXmlFiles;
|
||||
}
|
||||
|
||||
public Map<String, String> getJettyProperties()
|
||||
{
|
||||
return jettyProperties;
|
||||
}
|
||||
|
||||
public void setJettyProperties(Map<String, String> jettyProperties)
|
||||
{
|
||||
this.jettyProperties = jettyProperties;
|
||||
}
|
||||
|
||||
public ShutdownMonitor getShutdownMonitor()
|
||||
{
|
||||
return shutdownMonitor;
|
||||
}
|
||||
|
||||
public void setShutdownMonitor(ShutdownMonitor shutdownMonitor)
|
||||
{
|
||||
this.shutdownMonitor = shutdownMonitor;
|
||||
}
|
||||
|
||||
public int getStopPort()
|
||||
{
|
||||
return stopPort;
|
||||
}
|
||||
|
||||
public void setStopPort(int stopPort)
|
||||
{
|
||||
this.stopPort = stopPort;
|
||||
}
|
||||
|
||||
public String getStopKey()
|
||||
{
|
||||
return stopKey;
|
||||
}
|
||||
|
||||
public void setStopKey(String stopKey)
|
||||
{
|
||||
this.stopKey = stopKey;
|
||||
}
|
||||
|
||||
public void setWebApp(MavenWebAppContext app)
|
||||
{
|
||||
webApp = app;
|
||||
}
|
||||
|
||||
public void setWebAppProperties(Properties props)
|
||||
{
|
||||
if (webAppProperties != null)
|
||||
webAppProperties.clear();
|
||||
|
||||
if (props != null)
|
||||
{
|
||||
if (webAppProperties == null)
|
||||
webAppProperties = new Properties();
|
||||
|
||||
webAppProperties.putAll(props);
|
||||
}
|
||||
}
|
||||
|
||||
public String getContextXml()
|
||||
{
|
||||
return contextXml;
|
||||
}
|
||||
|
||||
public void setContextXml(String contextXml)
|
||||
{
|
||||
this.contextXml = contextXml;
|
||||
}
|
||||
|
||||
public void doStart() throws Exception
|
||||
{
|
||||
super.doStart();
|
||||
|
||||
configure();
|
||||
configureShutdownMonitor();
|
||||
server.start();
|
||||
}
|
||||
|
||||
protected void redeployWebApp() throws Exception
|
||||
{
|
||||
if (!webApp.isStopped())
|
||||
webApp.stop();
|
||||
stopWebApp();
|
||||
|
||||
//clear the ServletHandler, which may have
|
||||
//remembered "durable" Servlets, Filters, Listeners
|
||||
|
@ -239,40 +59,22 @@ public class JettyEmbedder extends AbstractLifeCycle
|
|||
|
||||
webApp.start();
|
||||
}
|
||||
|
||||
protected void join() throws InterruptedException
|
||||
|
||||
@Override
|
||||
public void stopWebApp() throws Exception
|
||||
{
|
||||
server.join();
|
||||
if (webApp != null && !webApp.isStopped())
|
||||
webApp.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the server and the webapp
|
||||
* Configure the webapp
|
||||
* @throws Exception if there is an unspecified problem
|
||||
*/
|
||||
private void configure() throws Exception
|
||||
public void configureWebApp() throws Exception
|
||||
{
|
||||
// apply any configs from jetty.xml files first
|
||||
Server tmp = ServerSupport.applyXmlConfigurations(new Server(), jettyXmlFiles, jettyProperties);
|
||||
|
||||
if (tmp != null)
|
||||
server = tmp;
|
||||
|
||||
server.setStopAtShutdown(stopAtShutdown);
|
||||
|
||||
//ensure there's a connector
|
||||
if (httpConnector != null)
|
||||
httpConnector.setServer(server);
|
||||
|
||||
ServerSupport.configureConnectors(server, httpConnector, jettyProperties);
|
||||
|
||||
//set up handler structure
|
||||
ServerSupport.configureHandlers(server, contextHandlers, requestLog);
|
||||
|
||||
//Set up list of default Configurations to apply to a webapp
|
||||
ServerSupport.configureDefaultConfigurationClasses(server);
|
||||
|
||||
// set up security realms
|
||||
ServerSupport.configureLoginServices(server, loginServices);
|
||||
Configurations.setServerDefault(server);
|
||||
|
||||
/* Configure the webapp */
|
||||
if (webApp == null)
|
||||
|
@ -286,37 +88,22 @@ public class JettyEmbedder extends AbstractLifeCycle
|
|||
Path qs = webApp.getTempDirectory().toPath().resolve("quickstart-web.xml");
|
||||
if (Files.exists(qs) && Files.isRegularFile(qs))
|
||||
{
|
||||
webApp.setAttribute(QuickStartConfiguration.QUICKSTART_WEB_XML, qs);
|
||||
webApp.addConfiguration(new MavenQuickStartConfiguration());
|
||||
webApp.setAttribute(QuickStartConfiguration.QUICKSTART_WEB_XML, qs);
|
||||
webApp.setAttribute(QuickStartConfiguration.MODE, Mode.QUICKSTART);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void applyWebAppProperties() throws Exception
|
||||
{
|
||||
super.applyWebAppProperties();
|
||||
WebAppPropertyConverter.fromProperties(webApp, webAppProperties, server, jettyProperties);
|
||||
}
|
||||
|
||||
public void addWebAppToServer() throws Exception
|
||||
{
|
||||
//add the webapp to the server
|
||||
ServerSupport.addWebApplication(server, webApp);
|
||||
}
|
||||
|
||||
private void applyWebAppProperties() throws Exception
|
||||
{
|
||||
//apply properties to the webapp if there are any
|
||||
if (contextXml != null)
|
||||
{
|
||||
if (webAppProperties == null)
|
||||
webAppProperties = new Properties();
|
||||
|
||||
webAppProperties.put("context.xml", contextXml);
|
||||
}
|
||||
WebAppPropertyConverter.fromProperties(webApp, webAppProperties, server, jettyProperties);
|
||||
}
|
||||
|
||||
private void configureShutdownMonitor()
|
||||
{
|
||||
if (stopPort > 0 && stopKey != null)
|
||||
{
|
||||
ShutdownMonitor monitor = ShutdownMonitor.getInstance();
|
||||
monitor.setPort(stopPort);
|
||||
monitor.setKey(stopKey);
|
||||
monitor.setExitVm(exitVm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ import java.util.Objects;
|
|||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.maven.AbstractForkedChild;
|
||||
import org.eclipse.jetty.maven.AbstractJettyEmbedder;
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
|
@ -38,174 +40,23 @@ import org.slf4j.LoggerFactory;
|
|||
* This is the class that is executed when the jetty maven plugin
|
||||
* forks a process when DeploymentMode=FORKED.
|
||||
*/
|
||||
public class JettyForkedChild extends ContainerLifeCycle
|
||||
public class JettyForkedChild extends AbstractForkedChild
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JettyForkedChild.class);
|
||||
|
||||
protected JettyEmbedder jetty;
|
||||
protected File tokenFile; // TODO: convert to Path
|
||||
protected Scanner scanner;
|
||||
protected File webAppPropsFile; // TODO: convert to Path
|
||||
protected int scanInterval;
|
||||
|
||||
/**
|
||||
* @param args arguments that were passed to main
|
||||
* @throws Exception if unable to configure
|
||||
*/
|
||||
public JettyForkedChild(String[] args)
|
||||
throws Exception
|
||||
public JettyForkedChild(String[] args) throws Exception
|
||||
{
|
||||
jetty = new JettyEmbedder();
|
||||
configure(args);
|
||||
super(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on the args passed to the program, configure jetty.
|
||||
*
|
||||
* @param args args that were passed to the program.
|
||||
* @throws Exception if unable to load webprops
|
||||
*/
|
||||
public void configure(String[] args)
|
||||
throws Exception
|
||||
@Override
|
||||
protected AbstractJettyEmbedder newJettyEmbedder()
|
||||
{
|
||||
Map<String, String> jettyProperties = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < args.length; i++)
|
||||
{
|
||||
//--stop-port
|
||||
if ("--stop-port".equals(args[i]))
|
||||
{
|
||||
jetty.setStopPort(Integer.parseInt(args[++i]));
|
||||
continue;
|
||||
}
|
||||
|
||||
//--stop-key
|
||||
if ("--stop-key".equals(args[i]))
|
||||
{
|
||||
jetty.setStopKey(args[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
//--jettyXml
|
||||
if ("--jetty-xml".equals(args[i]))
|
||||
{
|
||||
List<File> jettyXmls = new ArrayList<>();
|
||||
String[] names = StringUtil.csvSplit(args[++i]);
|
||||
for (int j = 0; names != null && j < names.length; j++)
|
||||
{
|
||||
jettyXmls.add(new File(names[j].trim()));
|
||||
}
|
||||
jetty.setJettyXmlFiles(jettyXmls);
|
||||
continue;
|
||||
}
|
||||
//--webprops
|
||||
if ("--webprops".equals(args[i]))
|
||||
{
|
||||
webAppPropsFile = new File(args[++i].trim());
|
||||
jetty.setWebAppProperties(loadWebAppProps());
|
||||
continue;
|
||||
}
|
||||
|
||||
//--token
|
||||
if ("--token".equals(args[i]))
|
||||
{
|
||||
tokenFile = new File(args[++i].trim());
|
||||
continue;
|
||||
}
|
||||
|
||||
if ("--scanInterval".equals(args[i]))
|
||||
{
|
||||
scanInterval = Integer.parseInt(args[++i].trim());
|
||||
scanner = new Scanner();
|
||||
scanner.setReportExistingFilesOnStartup(false);
|
||||
scanner.setScanInterval(scanInterval);
|
||||
scanner.addListener(new Scanner.BulkListener()
|
||||
{
|
||||
public void filesChanged(Set<String> changes)
|
||||
{
|
||||
if (!Objects.isNull(scanner))
|
||||
{
|
||||
try
|
||||
{
|
||||
scanner.stop();
|
||||
if (!Objects.isNull(jetty.getWebApp()))
|
||||
{
|
||||
//stop the webapp
|
||||
jetty.getWebApp().stop();
|
||||
//reload the props
|
||||
jetty.setWebAppProperties(loadWebAppProps());
|
||||
jetty.setWebApp(jetty.getWebApp());
|
||||
//restart the webapp
|
||||
jetty.redeployWebApp();
|
||||
|
||||
//restart the scanner
|
||||
scanner.start();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.error("Error reconfiguring/restarting webapp after change in watched files", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!Objects.isNull(webAppPropsFile))
|
||||
scanner.addFile(webAppPropsFile.toPath());
|
||||
continue;
|
||||
}
|
||||
|
||||
//assume everything else is a jetty property to be passed in
|
||||
String[] tmp = args[i].trim().split("=");
|
||||
if (tmp.length == 2)
|
||||
{
|
||||
jettyProperties.put(tmp[0], tmp[1]);
|
||||
}
|
||||
}
|
||||
|
||||
jetty.setJettyProperties(jettyProperties);
|
||||
jetty.setExitVm(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load properties from a file describing the webapp if one is
|
||||
* present.
|
||||
*
|
||||
* @return file contents as properties
|
||||
* @throws IOException if there is an IO problem
|
||||
*/
|
||||
private Properties loadWebAppProps() throws IOException
|
||||
{
|
||||
Properties props = new Properties();
|
||||
if (Objects.nonNull(webAppPropsFile))
|
||||
props.load(new FileInputStream(webAppPropsFile));
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a jetty instance and webapp. This thread will
|
||||
* wait until jetty exits.
|
||||
*/
|
||||
public void doStart()
|
||||
throws Exception
|
||||
{
|
||||
super.doStart();
|
||||
|
||||
//Start the embedded jetty instance
|
||||
jetty.start();
|
||||
|
||||
//touch file to signify start of jetty
|
||||
Path tokenPath = tokenFile.toPath();
|
||||
Files.createFile(tokenPath);
|
||||
|
||||
//Start a watcher on a file that will change if the
|
||||
//webapp is regenerated; stop the webapp, apply the
|
||||
//properties and restart it.
|
||||
if (scanner != null)
|
||||
scanner.start();
|
||||
|
||||
//wait for jetty to finish
|
||||
jetty.join();
|
||||
return new JettyEmbedder();
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
|
|
|
@ -13,94 +13,21 @@
|
|||
|
||||
package org.eclipse.jetty.ee10.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.maven.AbstractServerForker;
|
||||
|
||||
/**
|
||||
* JettyForker
|
||||
*
|
||||
* Uses quickstart to generate a webapp and forks a process to run it.
|
||||
*/
|
||||
public class JettyForker extends AbstractForker
|
||||
public class JettyForker extends AbstractServerForker
|
||||
{
|
||||
protected File forkWebXml;
|
||||
protected Server server;
|
||||
protected MavenWebAppContext webApp;
|
||||
protected String containerClassPath;
|
||||
protected File webAppPropsFile;
|
||||
protected String contextXml;
|
||||
protected int scanInterval;
|
||||
QuickStartGenerator generator;
|
||||
|
||||
/**
|
||||
* @return the scan
|
||||
*/
|
||||
public boolean isScan()
|
||||
public JettyForker()
|
||||
{
|
||||
return scanInterval > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if true, the forked child will scan for changes at 1 second intervals.
|
||||
* @param scan if true, the forked child will scan for changes at 1 second intervals
|
||||
*/
|
||||
public void setScan(boolean scan)
|
||||
{
|
||||
setScanInterval(scan ? 1 : 0);
|
||||
}
|
||||
|
||||
public void setScanInterval(int sec)
|
||||
{
|
||||
scanInterval = sec;
|
||||
}
|
||||
|
||||
public int getScanInterval()
|
||||
{
|
||||
return scanInterval;
|
||||
}
|
||||
|
||||
public File getWebAppPropsFile()
|
||||
{
|
||||
return webAppPropsFile;
|
||||
}
|
||||
|
||||
public void setWebAppPropsFile(File webAppPropsFile)
|
||||
{
|
||||
this.webAppPropsFile = webAppPropsFile;
|
||||
}
|
||||
|
||||
public File getForkWebXml()
|
||||
{
|
||||
return forkWebXml;
|
||||
}
|
||||
|
||||
public void setForkWebXml(File forkWebXml)
|
||||
{
|
||||
this.forkWebXml = forkWebXml;
|
||||
}
|
||||
|
||||
public String getContextXml()
|
||||
{
|
||||
return contextXml;
|
||||
}
|
||||
|
||||
public void setContextXml(String contextXml)
|
||||
{
|
||||
this.contextXml = contextXml;
|
||||
}
|
||||
|
||||
public String getContainerClassPath()
|
||||
{
|
||||
return containerClassPath;
|
||||
}
|
||||
|
||||
public void setContainerClassPath(String containerClassPath)
|
||||
{
|
||||
this.containerClassPath = containerClassPath;
|
||||
executionClassName = JettyForkedChild.class.getCanonicalName();
|
||||
}
|
||||
|
||||
public void setWebApp(MavenWebAppContext app)
|
||||
|
@ -108,19 +35,8 @@ public class JettyForker extends AbstractForker
|
|||
webApp = app;
|
||||
}
|
||||
|
||||
public Server getServer()
|
||||
{
|
||||
return server;
|
||||
}
|
||||
|
||||
public void setServer(Server server)
|
||||
{
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doStart()
|
||||
throws Exception
|
||||
public void generateWebApp() throws Exception
|
||||
{
|
||||
//Run the webapp to create the quickstart file and properties file
|
||||
generator = new QuickStartGenerator(forkWebXml.toPath(), webApp);
|
||||
|
@ -128,8 +44,6 @@ public class JettyForker extends AbstractForker
|
|||
generator.setWebAppProps(webAppPropsFile.toPath());
|
||||
generator.setServer(server);
|
||||
generator.generate();
|
||||
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
protected void redeployWebApp()
|
||||
|
@ -139,154 +53,4 @@ public class JettyForker extends AbstractForker
|
|||
//which will redeploy the webapp
|
||||
generator.generate();
|
||||
}
|
||||
|
||||
public ProcessBuilder createCommand()
|
||||
{
|
||||
List<String> cmd = new ArrayList<String>();
|
||||
cmd.add(getJavaBin());
|
||||
|
||||
if (jvmArgs != null)
|
||||
{
|
||||
String[] args = jvmArgs.split(" ");
|
||||
for (int i = 0; args != null && i < args.length; i++)
|
||||
{
|
||||
if (args[i] != null && !"".equals(args[i]))
|
||||
cmd.add(args[i].trim());
|
||||
}
|
||||
}
|
||||
|
||||
if (systemProperties != null)
|
||||
{
|
||||
for (Map.Entry<String, String> e:systemProperties.entrySet())
|
||||
{
|
||||
cmd.add("-D" + e.getKey() + "=" + e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (containerClassPath != null && containerClassPath.length() > 0)
|
||||
{
|
||||
cmd.add("-cp");
|
||||
cmd.add(containerClassPath);
|
||||
}
|
||||
|
||||
cmd.add(JettyForkedChild.class.getCanonicalName());
|
||||
|
||||
if (stopPort > 0 && stopKey != null)
|
||||
{
|
||||
cmd.add("--stop-port");
|
||||
cmd.add(Integer.toString(stopPort));
|
||||
cmd.add("--stop-key");
|
||||
cmd.add(stopKey);
|
||||
}
|
||||
if (jettyXmlFiles != null)
|
||||
{
|
||||
cmd.add("--jetty-xml");
|
||||
StringBuilder tmp = new StringBuilder();
|
||||
for (File jettyXml:jettyXmlFiles)
|
||||
{
|
||||
if (tmp.length() != 0)
|
||||
tmp.append(",");
|
||||
tmp.append(jettyXml.getAbsolutePath());
|
||||
}
|
||||
cmd.add(tmp.toString());
|
||||
}
|
||||
|
||||
cmd.add("--webprops");
|
||||
cmd.add(webAppPropsFile.getAbsolutePath());
|
||||
|
||||
cmd.add("--token");
|
||||
cmd.add(tokenFile.getAbsolutePath());
|
||||
|
||||
if (scanInterval > 0)
|
||||
{
|
||||
cmd.add("--scanInterval");
|
||||
cmd.add(Integer.toString(scanInterval));
|
||||
}
|
||||
|
||||
if (jettyProperties != null)
|
||||
{
|
||||
for (Map.Entry<String, String> e:jettyProperties.entrySet())
|
||||
{
|
||||
cmd.add(e.getKey() + "=" + e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
ProcessBuilder command = new ProcessBuilder(cmd);
|
||||
command.directory(workDir);
|
||||
|
||||
if (PluginLog.getLog().isDebugEnabled())
|
||||
PluginLog.getLog().debug("Forked cli:" + command.command());
|
||||
|
||||
PluginLog.getLog().info("Forked process starting");
|
||||
|
||||
//set up extra environment vars if there are any
|
||||
if (env != null && !env.isEmpty())
|
||||
command.environment().putAll(env);
|
||||
|
||||
if (waitForChild)
|
||||
{
|
||||
command.inheritIO();
|
||||
}
|
||||
else
|
||||
{
|
||||
command.redirectOutput(jettyOutputFile);
|
||||
command.redirectErrorStream(true);
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the location of the java binary.
|
||||
* @return the location of the java binary
|
||||
*/
|
||||
private String getJavaBin()
|
||||
{
|
||||
String[] javaexes = new String[]{"java", "java.exe"};
|
||||
|
||||
File javaHomeDir = new File(System.getProperty("java.home"));
|
||||
for (String javaexe : javaexes)
|
||||
{
|
||||
File javabin = new File(javaHomeDir, fileSeparators("bin/" + javaexe));
|
||||
if (javabin.exists() && javabin.isFile())
|
||||
{
|
||||
return javabin.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
return "java";
|
||||
}
|
||||
|
||||
public static String fileSeparators(String path)
|
||||
{
|
||||
StringBuilder ret = new StringBuilder();
|
||||
for (char c : path.toCharArray())
|
||||
{
|
||||
if ((c == '/') || (c == '\\'))
|
||||
{
|
||||
ret.append(File.separatorChar);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.append(c);
|
||||
}
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
public static String pathSeparators(String path)
|
||||
{
|
||||
StringBuilder ret = new StringBuilder();
|
||||
for (char c : path.toCharArray())
|
||||
{
|
||||
if ((c == ',') || (c == ':'))
|
||||
{
|
||||
ret.append(File.pathSeparatorChar);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.append(c);
|
||||
}
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,30 +14,8 @@
|
|||
package org.eclipse.jetty.ee10.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
import org.eclipse.jetty.maven.AbstractHomeForker;
|
||||
|
||||
/**
|
||||
* JettyHomeBaseForker
|
||||
|
@ -45,121 +23,13 @@ import org.eclipse.jetty.util.resource.ResourceFactory;
|
|||
* Unpacks a jetty-home and configures it with a base that allows it
|
||||
* to run an unassembled webapp.
|
||||
*/
|
||||
public class JettyHomeForker extends AbstractForker
|
||||
public class JettyHomeForker extends AbstractHomeForker
|
||||
{
|
||||
protected MavenWebAppContext webApp;
|
||||
|
||||
protected String contextXml;
|
||||
|
||||
/**
|
||||
* Location of existing jetty home directory
|
||||
*/
|
||||
protected File jettyHome;
|
||||
|
||||
/**
|
||||
* Zip of jetty-home
|
||||
*/
|
||||
protected File jettyHomeZip;
|
||||
|
||||
/**
|
||||
* Location of existing jetty base directory
|
||||
*/
|
||||
protected File jettyBase;
|
||||
|
||||
protected File baseDir;
|
||||
|
||||
/**
|
||||
* Optional list of other modules to
|
||||
* activate.
|
||||
*/
|
||||
protected String[] modules;
|
||||
|
||||
/*
|
||||
* Optional jetty commands
|
||||
*/
|
||||
protected String jettyOptions;
|
||||
|
||||
protected List<File> libExtJarFiles;
|
||||
protected Path modulesPath;
|
||||
protected Path etcPath;
|
||||
protected Path libPath;
|
||||
protected Path webappPath;
|
||||
protected Path mavenLibPath;
|
||||
protected String version;
|
||||
|
||||
public void setJettyOptions(String jettyOptions)
|
||||
public JettyHomeForker()
|
||||
{
|
||||
this.jettyOptions = jettyOptions;
|
||||
}
|
||||
|
||||
public String getJettyOptions()
|
||||
{
|
||||
return jettyOptions;
|
||||
}
|
||||
|
||||
public List<File> getLibExtJarFiles()
|
||||
{
|
||||
return libExtJarFiles;
|
||||
}
|
||||
|
||||
public void setLibExtJarFiles(List<File> libExtJarFiles)
|
||||
{
|
||||
this.libExtJarFiles = libExtJarFiles;
|
||||
}
|
||||
|
||||
public File getJettyHome()
|
||||
{
|
||||
return jettyHome;
|
||||
}
|
||||
|
||||
public void setJettyHome(File jettyHome)
|
||||
{
|
||||
this.jettyHome = jettyHome;
|
||||
}
|
||||
|
||||
public File getJettyBase()
|
||||
{
|
||||
return jettyBase;
|
||||
}
|
||||
|
||||
public void setJettyBase(File jettyBase)
|
||||
{
|
||||
this.jettyBase = jettyBase;
|
||||
}
|
||||
|
||||
public String[] getModules()
|
||||
{
|
||||
return modules;
|
||||
}
|
||||
|
||||
public void setModules(String[] modules)
|
||||
{
|
||||
this.modules = modules;
|
||||
}
|
||||
|
||||
public String getContextXmlFile()
|
||||
{
|
||||
return contextXml;
|
||||
}
|
||||
|
||||
public void setContextXml(String contextXml)
|
||||
{
|
||||
this.contextXml = contextXml;
|
||||
}
|
||||
|
||||
public File getJettyHomeZip()
|
||||
{
|
||||
return jettyHomeZip;
|
||||
}
|
||||
|
||||
public void setJettyHomeZip(File jettyHomeZip)
|
||||
{
|
||||
this.jettyHomeZip = jettyHomeZip;
|
||||
}
|
||||
|
||||
public MavenWebAppContext getWebApp()
|
||||
{
|
||||
return webApp;
|
||||
environment = "ee10";
|
||||
}
|
||||
|
||||
public void setWebApp(MavenWebAppContext webApp)
|
||||
|
@ -177,106 +47,6 @@ public class JettyHomeForker extends AbstractForker
|
|||
this.baseDir = baseDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProcessBuilder createCommand()
|
||||
{
|
||||
List<String> cmd = new ArrayList<>();
|
||||
cmd.add("java");
|
||||
|
||||
//add any args to the jvm
|
||||
if (StringUtil.isNotBlank(jvmArgs))
|
||||
{
|
||||
Arrays.stream(jvmArgs.split(" ")).filter(StringUtil::isNotBlank).forEach((a) -> cmd.add(a.trim()));
|
||||
}
|
||||
|
||||
cmd.add("-jar");
|
||||
cmd.add(new File(jettyHome, "start.jar").getAbsolutePath());
|
||||
|
||||
if (systemProperties != null)
|
||||
{
|
||||
for (Map.Entry<String, String> e : systemProperties.entrySet())
|
||||
{
|
||||
cmd.add("-D" + e.getKey() + "=" + e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
cmd.add("-DSTOP.PORT=" + stopPort);
|
||||
if (stopKey != null)
|
||||
cmd.add("-DSTOP.KEY=" + stopKey);
|
||||
|
||||
//set up enabled jetty modules
|
||||
StringBuilder tmp = new StringBuilder();
|
||||
tmp.append("--module=");
|
||||
tmp.append("server,http,ee10-webapp,ee10-deploy");
|
||||
if (modules != null)
|
||||
{
|
||||
for (String m : modules)
|
||||
{
|
||||
if (tmp.indexOf(m) < 0)
|
||||
tmp.append("," + m);
|
||||
}
|
||||
}
|
||||
|
||||
if (libExtJarFiles != null && !libExtJarFiles.isEmpty() && tmp.indexOf("ext") < 0)
|
||||
tmp.append(",ext");
|
||||
tmp.append(",ee10-maven");
|
||||
cmd.add(tmp.toString());
|
||||
|
||||
//put any other jetty options onto the command line
|
||||
if (StringUtil.isNotBlank(jettyOptions))
|
||||
{
|
||||
Arrays.stream(jettyOptions.split(" ")).filter(StringUtil::isNotBlank).forEach((a) -> cmd.add(a.trim()));
|
||||
}
|
||||
|
||||
//put any jetty properties onto the command line
|
||||
if (jettyProperties != null)
|
||||
{
|
||||
for (Map.Entry<String, String> e : jettyProperties.entrySet())
|
||||
{
|
||||
cmd.add(e.getKey() + "=" + e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
//existence of this file signals process started
|
||||
cmd.add("jetty.token.file=" + tokenFile.getAbsolutePath().toString());
|
||||
|
||||
ProcessBuilder builder = new ProcessBuilder(cmd);
|
||||
builder.directory(workDir);
|
||||
|
||||
PluginLog.getLog().info("Home process starting");
|
||||
|
||||
//set up extra environment vars if there are any
|
||||
if (!env.isEmpty())
|
||||
builder.environment().putAll(env);
|
||||
|
||||
if (waitForChild)
|
||||
builder.inheritIO();
|
||||
else
|
||||
{
|
||||
builder.redirectOutput(jettyOutputFile);
|
||||
builder.redirectErrorStream(true);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doStart() throws Exception
|
||||
{
|
||||
//set up a jetty-home
|
||||
configureJettyHome();
|
||||
|
||||
if (jettyHome == null || !jettyHome.exists())
|
||||
throw new IllegalStateException("No jetty home");
|
||||
|
||||
//set up a jetty-base
|
||||
configureJettyBase();
|
||||
|
||||
//convert the webapp to properties
|
||||
generateWebAppPropertiesFile();
|
||||
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
protected void redeployWebApp()
|
||||
throws Exception
|
||||
{
|
||||
|
@ -284,142 +54,9 @@ public class JettyHomeForker extends AbstractForker
|
|||
webappPath.resolve("maven.xml").toFile().setLastModified(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
private void generateWebAppPropertiesFile()
|
||||
protected void generateWebAppPropertiesFile()
|
||||
throws Exception
|
||||
{
|
||||
WebAppPropertyConverter.toProperties(webApp, etcPath.resolve("maven.props").toFile(), contextXml);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or configure a jetty base.
|
||||
*/
|
||||
private void configureJettyBase() throws Exception
|
||||
{
|
||||
if (jettyBase != null && !jettyBase.exists())
|
||||
throw new IllegalStateException(jettyBase.getAbsolutePath() + " does not exist");
|
||||
|
||||
File targetJettyBase = new File(baseDir, "jetty-base");
|
||||
Path targetBasePath = targetJettyBase.toPath();
|
||||
if (Files.exists(targetBasePath))
|
||||
IO.delete(targetJettyBase);
|
||||
|
||||
targetJettyBase.mkdirs();
|
||||
|
||||
//jetty-base will be the working directory for the forked command
|
||||
workDir = targetJettyBase;
|
||||
|
||||
//if there is an existing jetty base, copy parts of it
|
||||
if (jettyBase != null)
|
||||
{
|
||||
Path jettyBasePath = jettyBase.toPath();
|
||||
|
||||
final File contextXmlFile = (contextXml == null ? null : FileSystems.getDefault().getPath(contextXml).toFile());
|
||||
|
||||
//copy the existing jetty base
|
||||
Files.walkFileTree(jettyBasePath, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
|
||||
new SimpleFileVisitor<Path>()
|
||||
{
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException
|
||||
{
|
||||
Path targetDir = targetBasePath.resolve(jettyBasePath.relativize(dir));
|
||||
try
|
||||
{
|
||||
Files.copy(dir, targetDir);
|
||||
}
|
||||
catch (FileAlreadyExistsException e)
|
||||
{
|
||||
if (!Files.isDirectory(targetDir)) //ignore attempt to recreate dir
|
||||
throw e;
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException
|
||||
{
|
||||
if (contextXmlFile != null && Files.isSameFile(contextXmlFile.toPath(), file))
|
||||
return FileVisitResult.CONTINUE; //skip copying the context xml file
|
||||
Files.copy(file, targetBasePath.resolve(jettyBasePath.relativize(file)));
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//make the jetty base structure
|
||||
modulesPath = Files.createDirectories(targetBasePath.resolve("modules"));
|
||||
etcPath = Files.createDirectories(targetBasePath.resolve("etc"));
|
||||
libPath = Files.createDirectories(targetBasePath.resolve("lib"));
|
||||
webappPath = Files.createDirectories(targetBasePath.resolve("webapps"));
|
||||
mavenLibPath = Files.createDirectories(libPath.resolve("maven-ee10"));
|
||||
|
||||
//copy in the jetty-maven-plugin jar
|
||||
URI thisJar = TypeUtil.getLocationOfClass(this.getClass());
|
||||
if (thisJar == null)
|
||||
throw new IllegalStateException("Can't find jar for jetty-ee10-maven-plugin");
|
||||
|
||||
try (InputStream jarStream = thisJar.toURL().openStream();
|
||||
FileOutputStream fileStream = new FileOutputStream(mavenLibPath.resolve("plugin.jar").toFile()))
|
||||
{
|
||||
IO.copy(jarStream, fileStream);
|
||||
}
|
||||
|
||||
// copy in the maven.xml webapp file
|
||||
try (InputStream mavenXmlStream = getClass().getClassLoader().getResourceAsStream("maven-ee10.xml");
|
||||
FileOutputStream fileStream = new FileOutputStream(webappPath.resolve("maven-ee10.xml").toFile()))
|
||||
{
|
||||
IO.copy(mavenXmlStream, fileStream);
|
||||
}
|
||||
|
||||
Files.writeString(webappPath.resolve("maven-ee10.properties"), "environment=ee10");
|
||||
|
||||
//copy in the maven.mod file
|
||||
try (InputStream mavenModStream = getClass().getClassLoader().getResourceAsStream("ee10-maven.mod");
|
||||
FileOutputStream fileStream = new FileOutputStream(modulesPath.resolve("ee10-maven.mod").toFile()))
|
||||
{
|
||||
IO.copy(mavenModStream, fileStream);
|
||||
}
|
||||
|
||||
//copy in the jetty-maven.xml file
|
||||
try (InputStream jettyMavenStream = getClass().getClassLoader().getResourceAsStream("jetty-ee10-maven.xml");
|
||||
FileOutputStream fileStream = new FileOutputStream(etcPath.resolve("jetty-ee10-maven.xml").toFile()))
|
||||
{
|
||||
IO.copy(jettyMavenStream, fileStream);
|
||||
}
|
||||
|
||||
//if there were plugin dependencies, copy them into lib/ext
|
||||
if (libExtJarFiles != null && !libExtJarFiles.isEmpty())
|
||||
{
|
||||
Path libExtPath = Files.createDirectories(libPath.resolve("ext"));
|
||||
for (File f : libExtJarFiles)
|
||||
{
|
||||
try (InputStream jarStream = new FileInputStream(f);
|
||||
FileOutputStream fileStream = new FileOutputStream(libExtPath.resolve(f.getName()).toFile()))
|
||||
{
|
||||
IO.copy(jarStream, fileStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void configureJettyHome()
|
||||
throws Exception
|
||||
{
|
||||
if (jettyHome == null && jettyHomeZip == null)
|
||||
throw new IllegalStateException("No jettyHome");
|
||||
|
||||
if (baseDir == null)
|
||||
throw new IllegalStateException("No baseDir");
|
||||
|
||||
if (jettyHome == null)
|
||||
{
|
||||
try (ResourceFactory.Closeable resourceFactory = ResourceFactory.closeable())
|
||||
{
|
||||
Resource res = resourceFactory.newJarFileResource(jettyHomeZip.toPath().toUri());
|
||||
res.copyTo(baseDir.toPath()); // TODO: Resource.copyTo() cannot copy dir to dir, only file to file
|
||||
}
|
||||
//zip will unpack to target/jetty-home-<VERSION>
|
||||
jettyHome = new File(baseDir, "jetty-home-" + version);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.apache.maven.plugins.annotations.Mojo;
|
|||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.maven.ConsoleReader;
|
||||
import org.eclipse.jetty.util.IncludeExcludeSet;
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
|
@ -355,7 +356,7 @@ public class JettyRunMojo extends AbstractUnassembledWebAppMojo
|
|||
}
|
||||
}
|
||||
|
||||
embedder.getWebApp().stop();
|
||||
embedder.stopWebApp();
|
||||
configureWebApp();
|
||||
embedder.redeployWebApp();
|
||||
if (scanner != null)
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
|
|||
import org.apache.maven.plugins.annotations.Mojo;
|
||||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||
import org.eclipse.jetty.maven.ConsoleReader;
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
|
@ -235,7 +236,7 @@ public class JettyRunWarMojo extends AbstractWebAppMojo
|
|||
warArtifacts = null;
|
||||
configureScanner();
|
||||
}
|
||||
embedder.getWebApp().stop();
|
||||
embedder.stopWebApp();
|
||||
configureWebApp();
|
||||
embedder.redeployWebApp();
|
||||
scanner.start();
|
||||
|
|
|
@ -1,220 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
|
||||
/**
|
||||
* MavenResource
|
||||
*
|
||||
* A helper class to allow Resources to be used in maven pom.xml configuration by
|
||||
* providing a no-arg constructor and a setter that accepts a simple string as a
|
||||
* file location. This class delegates to a real Resource obtained using a
|
||||
* ResourceFactory.
|
||||
*/
|
||||
public class MavenResource extends Resource
|
||||
{
|
||||
private static final ResourceFactory __resourceFactory = ResourceFactory.root();
|
||||
private String _resourceString;
|
||||
private Resource _resource;
|
||||
|
||||
public MavenResource()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyTo(Path destination) throws IOException
|
||||
{
|
||||
if (_resource == null)
|
||||
return;
|
||||
_resource.copyTo(destination);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists()
|
||||
{
|
||||
if (_resource == null)
|
||||
return false;
|
||||
return _resource.exists();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Resource> getAllResources()
|
||||
{
|
||||
if (_resource == null)
|
||||
return null;
|
||||
return _resource.getAllResources();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileName()
|
||||
{
|
||||
if (_resource == null)
|
||||
return null;
|
||||
return _resource.getFileName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
if (_resource == null)
|
||||
return null;
|
||||
return _resource.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath()
|
||||
{
|
||||
if (_resource == null)
|
||||
return null;
|
||||
|
||||
return _resource.getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getRealURI()
|
||||
{
|
||||
if (_resource == null)
|
||||
return null;
|
||||
return _resource.getRealURI();
|
||||
}
|
||||
|
||||
public String getResourceAsString()
|
||||
{
|
||||
return _resourceString;
|
||||
}
|
||||
|
||||
public void setResourceAsString(String resourceString)
|
||||
{
|
||||
_resourceString = resourceString;
|
||||
_resource = __resourceFactory.newResource(_resourceString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI()
|
||||
{
|
||||
if (_resource == null)
|
||||
return null;
|
||||
|
||||
return _resource.getURI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlias()
|
||||
{
|
||||
if (_resource == null)
|
||||
return false;
|
||||
return _resource.isAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContainedIn(Resource container)
|
||||
{
|
||||
if (_resource == null)
|
||||
return false;
|
||||
return _resource.isContainedIn(container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Resource other)
|
||||
{
|
||||
if (_resource == null)
|
||||
return false;
|
||||
return _resource.contains(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPathTo(Resource other)
|
||||
{
|
||||
if (_resource == null)
|
||||
return null;
|
||||
return _resource.getPathTo(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory()
|
||||
{
|
||||
if (_resource == null)
|
||||
return false;
|
||||
|
||||
return _resource.isDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable()
|
||||
{
|
||||
if (_resource == null)
|
||||
return false;
|
||||
|
||||
return _resource.isReadable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Resource> iterator()
|
||||
{
|
||||
if (_resource == null)
|
||||
return null;
|
||||
return _resource.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant lastModified()
|
||||
{
|
||||
if (_resource == null)
|
||||
return null;
|
||||
return _resource.lastModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long length()
|
||||
{
|
||||
if (_resource == null)
|
||||
return -1;
|
||||
return _resource.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Resource> list()
|
||||
{
|
||||
if (_resource == null)
|
||||
return null;
|
||||
return _resource.list();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream newInputStream() throws IOException
|
||||
{
|
||||
if (_resource == null)
|
||||
return null;
|
||||
return _resource.newInputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource resolve(String subUriPath)
|
||||
{
|
||||
if (_resource == null)
|
||||
return null;
|
||||
return _resource.resolve(subUriPath);
|
||||
}
|
||||
}
|
|
@ -1,221 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.ConnectionFactory;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
|
||||
/**
|
||||
* MavenServerConnector
|
||||
*
|
||||
* As the ServerConnector class does not have a no-arg constructor, and moreover requires
|
||||
* the server instance passed in to all its constructors, it cannot
|
||||
* be referenced in the pom.xml. This class wraps a ServerConnector, delaying setting the
|
||||
* server instance. Only a few of the setters from the ServerConnector class are supported.
|
||||
*/
|
||||
public class MavenServerConnector extends ContainerLifeCycle implements Connector
|
||||
{
|
||||
public static String PORT_SYSPROPERTY = "jetty.http.port";
|
||||
|
||||
public static final int DEFAULT_PORT = 8080;
|
||||
public static final String DEFAULT_PORT_STR = String.valueOf(DEFAULT_PORT);
|
||||
public static final int DEFAULT_MAX_IDLE_TIME = 30000;
|
||||
|
||||
private Server server;
|
||||
private volatile ServerConnector delegate;
|
||||
private String host;
|
||||
private String name;
|
||||
private int port;
|
||||
private long idleTimeout;
|
||||
|
||||
public MavenServerConnector()
|
||||
{
|
||||
}
|
||||
|
||||
public void setServer(Server server)
|
||||
{
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public void setHost(String host)
|
||||
{
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public String getHost()
|
||||
{
|
||||
return this.host;
|
||||
}
|
||||
|
||||
public void setPort(int port)
|
||||
{
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public int getPort()
|
||||
{
|
||||
return this.port;
|
||||
}
|
||||
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setIdleTimeout(long idleTimeout)
|
||||
{
|
||||
this.idleTimeout = idleTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
|
||||
if (this.server == null)
|
||||
throw new IllegalStateException("Server not set for MavenServerConnector");
|
||||
|
||||
this.delegate = new ServerConnector(this.server);
|
||||
this.delegate.setName(this.name);
|
||||
this.delegate.setPort(this.port);
|
||||
this.delegate.setHost(this.host);
|
||||
this.delegate.setIdleTimeout(idleTimeout);
|
||||
this.delegate.start();
|
||||
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
this.delegate.stop();
|
||||
super.doStop();
|
||||
this.delegate = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> shutdown()
|
||||
{
|
||||
return checkDelegate().shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShutdown()
|
||||
{
|
||||
return checkDelegate().isShutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Server getServer()
|
||||
{
|
||||
return this.server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getExecutor()
|
||||
{
|
||||
return checkDelegate().getExecutor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scheduler getScheduler()
|
||||
{
|
||||
return checkDelegate().getScheduler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufferPool getByteBufferPool()
|
||||
{
|
||||
return checkDelegate().getByteBufferPool();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionFactory getConnectionFactory(String nextProtocol)
|
||||
{
|
||||
return checkDelegate().getConnectionFactory(nextProtocol);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getConnectionFactory(Class<T> factoryType)
|
||||
{
|
||||
return checkDelegate().getConnectionFactory(factoryType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionFactory getDefaultConnectionFactory()
|
||||
{
|
||||
return checkDelegate().getDefaultConnectionFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ConnectionFactory> getConnectionFactories()
|
||||
{
|
||||
return checkDelegate().getConnectionFactories();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getProtocols()
|
||||
{
|
||||
return checkDelegate().getProtocols();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ManagedAttribute("maximum time a connection can be idle before being closed (in ms)")
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
return checkDelegate().getIdleTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTransport()
|
||||
{
|
||||
return checkDelegate().getTransport();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<EndPoint> getConnectedEndPoints()
|
||||
{
|
||||
return checkDelegate().getConnectedEndPoints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public int getLocalPort()
|
||||
{
|
||||
return this.delegate.getLocalPort();
|
||||
}
|
||||
|
||||
private ServerConnector checkDelegate() throws IllegalStateException
|
||||
{
|
||||
ServerConnector d = this.delegate;
|
||||
if (d == null)
|
||||
throw new IllegalStateException("MavenServerConnector delegate not ready");
|
||||
return d;
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ import org.eclipse.jetty.ee10.webapp.Configuration;
|
|||
import org.eclipse.jetty.ee10.webapp.Configurations;
|
||||
import org.eclipse.jetty.ee10.webapp.MetaInfConfiguration;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.maven.Overlay;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
|
|
@ -1,103 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
||||
/**
|
||||
* Overlay
|
||||
*
|
||||
* An Overlay represents overlay information derived from the
|
||||
* maven-war-plugin.
|
||||
*/
|
||||
public class Overlay
|
||||
{
|
||||
private OverlayConfig _config;
|
||||
private Resource _resource;
|
||||
|
||||
public Overlay(OverlayConfig config, Resource resource)
|
||||
{
|
||||
_config = config;
|
||||
_resource = resource;
|
||||
}
|
||||
|
||||
public Overlay(OverlayConfig config)
|
||||
{
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public void setResource(Resource r)
|
||||
{
|
||||
_resource = r;
|
||||
}
|
||||
|
||||
public Resource getResource()
|
||||
{
|
||||
return _resource;
|
||||
}
|
||||
|
||||
public OverlayConfig getConfig()
|
||||
{
|
||||
return _config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder strbuff = new StringBuilder();
|
||||
if (_resource != null)
|
||||
strbuff.append(_resource);
|
||||
if (_config != null)
|
||||
{
|
||||
strbuff.append(" [");
|
||||
strbuff.append(_config);
|
||||
strbuff.append("]");
|
||||
}
|
||||
return strbuff.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpack the overlay into the given directory. Only
|
||||
* unpack if the directory does not exist, or the overlay
|
||||
* has been modified since the dir was created.
|
||||
*
|
||||
* @param dir the directory into which to unpack the overlay
|
||||
* @throws IOException
|
||||
*/
|
||||
public void unpackTo(File dir) throws IOException // TODO: change to Path
|
||||
{
|
||||
if (dir == null)
|
||||
throw new IllegalStateException("No overly unpack directory");
|
||||
Path pathDir = dir.toPath();
|
||||
// only unpack if the overlay is newer
|
||||
if (!Files.exists(pathDir))
|
||||
{
|
||||
// create directory
|
||||
Files.createDirectories(pathDir);
|
||||
getResource().copyTo(pathDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
Instant dirLastModified = Files.getLastModifiedTime(pathDir).toInstant();
|
||||
if (getResource().lastModified().isAfter(dirLastModified))
|
||||
getResource().copyTo(pathDir);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,337 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.codehaus.plexus.util.xml.Xpp3Dom;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
/**
|
||||
* OverlayConfig
|
||||
*
|
||||
* The configuration of a war overlay in a pom. Used to help determine which resources
|
||||
* from a project's dependent war should be included.
|
||||
*/
|
||||
public class OverlayConfig
|
||||
{
|
||||
private String targetPath;
|
||||
private String groupId;
|
||||
private String artifactId;
|
||||
private String classifier;
|
||||
private List<String> includes;
|
||||
private List<String> excludes;
|
||||
private boolean skip;
|
||||
private boolean filtered;
|
||||
|
||||
public OverlayConfig()
|
||||
{
|
||||
}
|
||||
|
||||
public OverlayConfig(String fmt, List<String> defaultIncludes, List<String> defaultExcludes)
|
||||
{
|
||||
if (fmt == null)
|
||||
return;
|
||||
String[] atoms = StringUtil.csvSplit(fmt);
|
||||
for (int i = 0; i < atoms.length; i++)
|
||||
{
|
||||
String s = atoms[i].trim();
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if (!"".equals(s))
|
||||
groupId = s;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
if (!"".equals(s))
|
||||
artifactId = s;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if (!"".equals(s))
|
||||
classifier = s;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
if (!"".equals(s))
|
||||
targetPath = s;
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
if ("".equals(s))
|
||||
skip = false;
|
||||
else
|
||||
skip = Boolean.valueOf(s);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
if ("".equals(s))
|
||||
filtered = false;
|
||||
else
|
||||
filtered = Boolean.valueOf(s);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
if ("".equals(s))
|
||||
break;
|
||||
String[] incs = s.split(";");
|
||||
if (incs.length > 0)
|
||||
includes = Arrays.asList(incs);
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
if ("".equals(s))
|
||||
break;
|
||||
String[] exs = s.split(";");
|
||||
if (exs.length > 0)
|
||||
excludes = Arrays.asList(exs);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public OverlayConfig(Xpp3Dom root, List<String> defaultIncludes, List<String> defaultExcludes)
|
||||
{
|
||||
Xpp3Dom node = root.getChild("groupId");
|
||||
setGroupId(node == null ? null : node.getValue());
|
||||
|
||||
node = root.getChild("artifactId");
|
||||
setArtifactId(node == null ? null : node.getValue());
|
||||
|
||||
node = root.getChild("classifier");
|
||||
setClassifier(node == null ? null : node.getValue());
|
||||
|
||||
node = root.getChild("targetPath");
|
||||
setTargetPath(node == null ? null : node.getValue());
|
||||
|
||||
node = root.getChild("skip");
|
||||
setSkip(node == null ? false : Boolean.valueOf(node.getValue()));
|
||||
|
||||
node = root.getChild("filtered");
|
||||
setFiltered(node == null ? false : Boolean.valueOf(node.getValue()));
|
||||
|
||||
node = root.getChild("includes");
|
||||
List<String> includes = null;
|
||||
if (node != null && node.getChildCount() > 0)
|
||||
{
|
||||
Xpp3Dom[] list = node.getChildren("include");
|
||||
for (int j = 0; list != null && j < list.length; j++)
|
||||
{
|
||||
if (includes == null)
|
||||
includes = new ArrayList<>();
|
||||
includes.add(list[j].getValue());
|
||||
}
|
||||
}
|
||||
if (includes == null && defaultIncludes != null)
|
||||
{
|
||||
includes = new ArrayList<>();
|
||||
includes.addAll(defaultIncludes);
|
||||
}
|
||||
setIncludes(includes);
|
||||
|
||||
node = root.getChild("excludes");
|
||||
List<String> excludes = null;
|
||||
if (node != null && node.getChildCount() > 0)
|
||||
{
|
||||
Xpp3Dom[] list = node.getChildren("exclude");
|
||||
for (int j = 0; list != null && j < list.length; j++)
|
||||
{
|
||||
if (excludes == null)
|
||||
excludes = new ArrayList<>();
|
||||
excludes.add(list[j].getValue());
|
||||
}
|
||||
}
|
||||
if (excludes == null && defaultExcludes != null)
|
||||
{
|
||||
excludes = new ArrayList<>();
|
||||
excludes.addAll(defaultExcludes);
|
||||
}
|
||||
setExcludes(excludes);
|
||||
}
|
||||
|
||||
public String getTargetPath()
|
||||
{
|
||||
return targetPath;
|
||||
}
|
||||
|
||||
public void setTargetPath(String targetPath)
|
||||
{
|
||||
this.targetPath = targetPath;
|
||||
}
|
||||
|
||||
public String getGroupId()
|
||||
{
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(String groupId)
|
||||
{
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public String getArtifactId()
|
||||
{
|
||||
return artifactId;
|
||||
}
|
||||
|
||||
public void setArtifactId(String artifactId)
|
||||
{
|
||||
this.artifactId = artifactId;
|
||||
}
|
||||
|
||||
public String getClassifier()
|
||||
{
|
||||
return classifier;
|
||||
}
|
||||
|
||||
public void setClassifier(String classifier)
|
||||
{
|
||||
this.classifier = classifier;
|
||||
}
|
||||
|
||||
public List<String> getIncludes()
|
||||
{
|
||||
return includes;
|
||||
}
|
||||
|
||||
public void setIncludes(List<String> includes)
|
||||
{
|
||||
this.includes = includes;
|
||||
}
|
||||
|
||||
public List<String> getExcludes()
|
||||
{
|
||||
return excludes;
|
||||
}
|
||||
|
||||
public void setExcludes(List<String> excludes)
|
||||
{
|
||||
this.excludes = excludes;
|
||||
}
|
||||
|
||||
public boolean isSkip()
|
||||
{
|
||||
return skip;
|
||||
}
|
||||
|
||||
public void setSkip(boolean skip)
|
||||
{
|
||||
this.skip = skip;
|
||||
}
|
||||
|
||||
public boolean isFiltered()
|
||||
{
|
||||
return filtered;
|
||||
}
|
||||
|
||||
public void setFiltered(boolean filtered)
|
||||
{
|
||||
this.filtered = filtered;
|
||||
}
|
||||
|
||||
public boolean isCurrentProject()
|
||||
{
|
||||
if (this.groupId == null && this.artifactId == null)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this overlay configuration matches an Artifact's info
|
||||
*
|
||||
* @param gid Artifact groupId
|
||||
* @param aid Artifact artifactId
|
||||
* @param cls Artifact classifier
|
||||
* @return true if matched
|
||||
*/
|
||||
public boolean matchesArtifact(String gid, String aid, String cls)
|
||||
{
|
||||
if (((getGroupId() == null && gid == null) || (getGroupId() != null && getGroupId().equals(gid))) &&
|
||||
((getArtifactId() == null && aid == null) || (getArtifactId() != null && getArtifactId().equals(aid))) &&
|
||||
((getClassifier() == null) || (getClassifier().equals(cls))))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this overlay configuration matches an Artifact's info
|
||||
*
|
||||
* @param gid the group id
|
||||
* @param aid the artifact id
|
||||
* @return true if matched
|
||||
*/
|
||||
public boolean matchesArtifact(String gid, String aid)
|
||||
{
|
||||
if (((getGroupId() == null && gid == null) || (getGroupId() != null && getGroupId().equals(gid))) &&
|
||||
((getArtifactId() == null && aid == null) || (getArtifactId() != null && getArtifactId().equals(aid))))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder strbuff = new StringBuilder();
|
||||
strbuff.append((groupId != null ? groupId : "") + ",");
|
||||
strbuff.append((artifactId != null ? artifactId : "") + ",");
|
||||
strbuff.append((classifier != null ? classifier : "") + ",");
|
||||
strbuff.append((targetPath != null ? targetPath : "") + ",");
|
||||
strbuff.append("" + skip + ",");
|
||||
strbuff.append("" + filtered + ",");
|
||||
|
||||
if (includes != null)
|
||||
{
|
||||
Iterator<String> itor = includes.iterator();
|
||||
while (itor.hasNext())
|
||||
{
|
||||
strbuff.append(itor.next());
|
||||
if (itor.hasNext())
|
||||
strbuff.append(";");
|
||||
}
|
||||
}
|
||||
|
||||
strbuff.append(", ");
|
||||
|
||||
if (excludes != null)
|
||||
{
|
||||
Iterator<String> itor = excludes.iterator();
|
||||
while (itor.hasNext())
|
||||
{
|
||||
strbuff.append(itor.next());
|
||||
if (itor.hasNext())
|
||||
strbuff.append(";");
|
||||
}
|
||||
}
|
||||
|
||||
return strbuff.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.MountedPathResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
|
||||
/**
|
||||
* OverlayManager
|
||||
*
|
||||
* Mediates information about overlays configured in a war plugin.
|
||||
*
|
||||
*/
|
||||
public class OverlayManager
|
||||
{
|
||||
private WarPluginInfo warPlugin;
|
||||
|
||||
public OverlayManager(WarPluginInfo warPlugin)
|
||||
{
|
||||
this.warPlugin = warPlugin;
|
||||
}
|
||||
|
||||
public void applyOverlays(MavenWebAppContext webApp) throws IOException
|
||||
{
|
||||
Objects.requireNonNull(webApp);
|
||||
List<Resource> resourceBases = new ArrayList<Resource>();
|
||||
|
||||
for (Overlay o : getOverlays(webApp))
|
||||
{
|
||||
//can refer to the current project in list of overlays for ordering purposes
|
||||
if (o.getConfig() != null && o.getConfig().isCurrentProject() && webApp.getBaseResource().exists())
|
||||
{
|
||||
resourceBases.add(webApp.getBaseResource());
|
||||
continue;
|
||||
}
|
||||
//add in the selectively unpacked overlay in the correct order to the webapp's resource base
|
||||
resourceBases.add(unpackOverlay(webApp, o));
|
||||
}
|
||||
|
||||
if (!resourceBases.contains(webApp.getBaseResource()) && webApp.getBaseResource().exists())
|
||||
{
|
||||
if (webApp.getBaseAppFirst())
|
||||
resourceBases.add(0, webApp.getBaseResource());
|
||||
else
|
||||
resourceBases.add(webApp.getBaseResource());
|
||||
}
|
||||
|
||||
webApp.setBaseResource(ResourceFactory.combine(resourceBases));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an ordered list of overlays
|
||||
*/
|
||||
protected List<Overlay> getOverlays(WebAppContext webApp)
|
||||
{
|
||||
Set<Artifact> matchedWarArtifacts = new HashSet<Artifact>();
|
||||
List<Overlay> overlays = new ArrayList<Overlay>();
|
||||
|
||||
//Check all of the overlay configurations
|
||||
for (OverlayConfig config:warPlugin.getMavenWarOverlayConfigs())
|
||||
{
|
||||
//overlays can be individually skipped
|
||||
if (config.isSkip())
|
||||
continue;
|
||||
|
||||
//an empty overlay refers to the current project - important for ordering
|
||||
if (config.isCurrentProject())
|
||||
{
|
||||
Overlay overlay = new Overlay(config, null);
|
||||
overlays.add(overlay);
|
||||
continue;
|
||||
}
|
||||
|
||||
//if a war matches an overlay config
|
||||
Artifact a = warPlugin.getWarArtifact(config.getGroupId(), config.getArtifactId(), config.getClassifier());
|
||||
if (a != null)
|
||||
{
|
||||
matchedWarArtifacts.add(a);
|
||||
Resource resource = webApp.getResourceFactory().newJarFileResource(a.getFile().toPath().toUri());
|
||||
SelectiveJarResource r = new SelectiveJarResource(resource);
|
||||
r.setIncludes(config.getIncludes());
|
||||
r.setExcludes(config.getExcludes());
|
||||
Overlay overlay = new Overlay(config, r);
|
||||
overlays.add(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
//iterate over the left over war artifacts add them
|
||||
for (Artifact a: warPlugin.getWarArtifacts())
|
||||
{
|
||||
if (!matchedWarArtifacts.contains(a))
|
||||
{
|
||||
Resource resource = webApp.getResourceFactory().newJarFileResource(a.getFile().toPath().toUri());
|
||||
Overlay overlay = new Overlay(null, resource);
|
||||
overlays.add(overlay);
|
||||
}
|
||||
}
|
||||
return overlays;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpack a war overlay.
|
||||
*
|
||||
* @param overlay the war overlay to unpack
|
||||
* @return the location to which it was unpacked
|
||||
* @throws IOException if there is an IO problem
|
||||
*/
|
||||
protected Resource unpackOverlay(WebAppContext webApp, Overlay overlay)
|
||||
throws IOException
|
||||
{
|
||||
Objects.requireNonNull(webApp);
|
||||
|
||||
if (overlay.getResource() == null)
|
||||
return null; //nothing to unpack
|
||||
|
||||
//Get the name of the overlayed war and unpack it to a dir of the
|
||||
//same name in the temporary directory.
|
||||
//We know it is a war because it came from the maven repo
|
||||
assert overlay.getResource() instanceof MountedPathResource;
|
||||
|
||||
Path p = Paths.get(URIUtil.unwrapContainer(overlay.getResource().getURI()));
|
||||
String name = p.getName(p.getNameCount() - 1).toString();
|
||||
name = name.replace('.', '_');
|
||||
|
||||
File overlaysDir = new File(warPlugin.getProject().getBuild().getDirectory(), "jetty_overlays");
|
||||
File dir = new File(overlaysDir, name);
|
||||
|
||||
//if specified targetPath, unpack to that subdir instead
|
||||
File unpackDir = dir;
|
||||
if (overlay.getConfig() != null && overlay.getConfig().getTargetPath() != null)
|
||||
unpackDir = new File(dir, overlay.getConfig().getTargetPath());
|
||||
|
||||
overlay.unpackTo(unpackDir);
|
||||
|
||||
//use top level of unpacked content
|
||||
return webApp.getResourceFactory().newResource(unpackDir.getCanonicalPath());
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin;
|
||||
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
|
||||
/**
|
||||
* PluginLog
|
||||
*
|
||||
* Convenience class to provide access to the plugin
|
||||
* Log for non-mojo classes.
|
||||
*/
|
||||
public class PluginLog
|
||||
{
|
||||
private static Log log = null;
|
||||
|
||||
public static void setLog(Log l)
|
||||
{
|
||||
log = l;
|
||||
}
|
||||
|
||||
public static Log getLog()
|
||||
{
|
||||
return log;
|
||||
}
|
||||
}
|
|
@ -18,6 +18,8 @@ import java.nio.file.Path;
|
|||
import org.eclipse.jetty.ee10.annotations.AnnotationConfiguration;
|
||||
import org.eclipse.jetty.ee10.quickstart.QuickStartConfiguration;
|
||||
import org.eclipse.jetty.ee10.quickstart.QuickStartConfiguration.Mode;
|
||||
import org.eclipse.jetty.ee10.webapp.Configurations;
|
||||
import org.eclipse.jetty.maven.ServerSupport;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
||||
|
@ -148,7 +150,7 @@ public class QuickStartGenerator
|
|||
//ensure handler structure enabled
|
||||
ServerSupport.configureHandlers(server, null, null);
|
||||
|
||||
ServerSupport.configureDefaultConfigurationClasses(server);
|
||||
Configurations.setServerDefault(server);
|
||||
|
||||
//if our server has a thread pool associated we can do annotation scanning multithreaded,
|
||||
//otherwise scanning will be single threaded
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ScanPattern
|
||||
*
|
||||
* Ant-style pattern of includes and excludes.
|
||||
*/
|
||||
public class ScanPattern
|
||||
{
|
||||
private List<String> _includes = Collections.emptyList();
|
||||
private List<String> _excludes = Collections.emptyList();
|
||||
|
||||
public void setIncludes(List<String> includes)
|
||||
{
|
||||
_includes = includes;
|
||||
}
|
||||
|
||||
public void setExcludes(List<String> excludes)
|
||||
{
|
||||
_excludes = excludes;
|
||||
}
|
||||
|
||||
public List<String> getIncludes()
|
||||
{
|
||||
return _includes;
|
||||
}
|
||||
|
||||
public List<String> getExcludes()
|
||||
{
|
||||
return _excludes;
|
||||
}
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.util.IncludeExcludeSet;
|
||||
|
||||
/**
|
||||
* ScanTargetPattern
|
||||
*
|
||||
* Utility class to provide the ability for the mvn jetty:run
|
||||
* mojo to be able to specify filesets of extra files to
|
||||
* regularly scan for changes in order to redeploy the webapp.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* <scanTargetPattern>
|
||||
* <directory>/some/place</directory>
|
||||
* <includes>
|
||||
* <include>some ant pattern here </include>
|
||||
* <include>some ant pattern here </include>
|
||||
* </includes>
|
||||
* <excludes>
|
||||
* <exclude>some ant pattern here </exclude>
|
||||
* <exclude>some ant pattern here </exclude>
|
||||
* </excludes>
|
||||
* </scanTargetPattern>
|
||||
*/
|
||||
public class ScanTargetPattern
|
||||
{
|
||||
private File _directory;
|
||||
private ScanPattern _pattern;
|
||||
|
||||
/**
|
||||
* Get the _directory.
|
||||
* @return the _directory
|
||||
*/
|
||||
public File getDirectory()
|
||||
{
|
||||
return _directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the directory to set.
|
||||
* @param directory the directory to set
|
||||
*/
|
||||
public void setDirectory(File directory)
|
||||
{
|
||||
this._directory = directory;
|
||||
}
|
||||
|
||||
public void setIncludes(List<String> includes)
|
||||
{
|
||||
if (_pattern == null)
|
||||
_pattern = new ScanPattern();
|
||||
_pattern.setIncludes(includes);
|
||||
}
|
||||
|
||||
public void setExcludes(List<String> excludes)
|
||||
{
|
||||
if (_pattern == null)
|
||||
_pattern = new ScanPattern();
|
||||
_pattern.setExcludes(excludes);
|
||||
}
|
||||
|
||||
public List<String> getIncludes()
|
||||
{
|
||||
return (_pattern == null ? Collections.emptyList() : _pattern.getIncludes());
|
||||
}
|
||||
|
||||
public List<String> getExcludes()
|
||||
{
|
||||
return (_pattern == null ? Collections.emptyList() : _pattern.getExcludes());
|
||||
}
|
||||
|
||||
public void configureIncludesExcludeSet(IncludeExcludeSet<PathMatcher, Path> includesExcludes)
|
||||
{
|
||||
for (String include:getIncludes())
|
||||
{
|
||||
if (!include.startsWith("glob:"))
|
||||
include = "glob:" + include;
|
||||
includesExcludes.include(_directory.toPath().getFileSystem().getPathMatcher(include));
|
||||
}
|
||||
|
||||
for (String exclude:getExcludes())
|
||||
{
|
||||
if (!exclude.startsWith("glob:"))
|
||||
exclude = "glob:" + exclude;
|
||||
includesExcludes.exclude(_directory.toPath().getFileSystem().getPathMatcher(exclude));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,280 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import org.codehaus.plexus.util.SelectorUtils;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* SelectiveJarResource
|
||||
*
|
||||
* Selectively copies resources from a jar file based on includes/excludes.
|
||||
* TODO: investigate if copyTo() can instead have an IncludeExcludeSet as a parameter?
|
||||
* TODO: or have a smaller ResourceWrapper jetty-core class that can be overridden for specific behavior like in this class
|
||||
*/
|
||||
public class SelectiveJarResource extends Resource
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SelectiveJarResource.class);
|
||||
|
||||
/**
|
||||
* Default matches every resource.
|
||||
*/
|
||||
public static final List<String> DEFAULT_INCLUDES =
|
||||
Arrays.asList(new String[]{"**"});
|
||||
|
||||
/**
|
||||
* Default is to exclude nothing.
|
||||
*/
|
||||
public static final List<String> DEFAULT_EXCLUDES = Collections.emptyList();
|
||||
|
||||
final Resource _delegate;
|
||||
List<String> _includes = null;
|
||||
List<String> _excludes = null;
|
||||
boolean _caseSensitive = false;
|
||||
|
||||
public SelectiveJarResource(Resource resource)
|
||||
{
|
||||
_delegate = resource;
|
||||
}
|
||||
|
||||
public void setCaseSensitive(boolean caseSensitive)
|
||||
{
|
||||
_caseSensitive = caseSensitive;
|
||||
}
|
||||
|
||||
public void setIncludes(List<String> patterns)
|
||||
{
|
||||
_includes = patterns;
|
||||
}
|
||||
|
||||
public void setExcludes(List<String> patterns)
|
||||
{
|
||||
_excludes = patterns;
|
||||
}
|
||||
|
||||
protected boolean isIncluded(String name)
|
||||
{
|
||||
for (String include : _includes)
|
||||
{
|
||||
if (SelectorUtils.matchPath(include, name, "/", _caseSensitive))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isExcluded(String name)
|
||||
{
|
||||
for (String exclude : _excludes)
|
||||
{
|
||||
if (SelectorUtils.matchPath(exclude, name, "/", _caseSensitive))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath()
|
||||
{
|
||||
return _delegate.getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory()
|
||||
{
|
||||
return _delegate.isDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant lastModified()
|
||||
{
|
||||
return _delegate.lastModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable()
|
||||
{
|
||||
return _delegate.isReadable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContainedIn(Resource container)
|
||||
{
|
||||
return _delegate.isContainedIn(container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Resource other)
|
||||
{
|
||||
return _delegate.contains(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPathTo(Resource other)
|
||||
{
|
||||
return _delegate.getPathTo(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI()
|
||||
{
|
||||
return _delegate.getURI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return _delegate.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileName()
|
||||
{
|
||||
return _delegate.getFileName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource resolve(String subUriPath)
|
||||
{
|
||||
return _delegate.resolve(subUriPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyTo(Path directory) throws IOException
|
||||
{
|
||||
if (_includes == null)
|
||||
_includes = DEFAULT_INCLUDES;
|
||||
if (_excludes == null)
|
||||
_excludes = DEFAULT_EXCLUDES;
|
||||
|
||||
//Copy contents of the jar file to the given directory,
|
||||
//using the includes and excludes patterns to control which
|
||||
//parts of the jar file are copied
|
||||
if (!exists())
|
||||
return;
|
||||
|
||||
String urlString = this.getURI().toASCIIString().trim();
|
||||
int endOfJarUrl = urlString.indexOf("!/");
|
||||
int startOfJarUrl = (endOfJarUrl >= 0 ? 4 : 0);
|
||||
|
||||
if (endOfJarUrl < 0)
|
||||
throw new IOException("Not a valid jar url: " + urlString);
|
||||
|
||||
URL jarFileURL = new URL(urlString.substring(startOfJarUrl, endOfJarUrl));
|
||||
|
||||
try (InputStream is = jarFileURL.openConnection().getInputStream();
|
||||
JarInputStream jin = new JarInputStream(is))
|
||||
{
|
||||
JarEntry entry;
|
||||
|
||||
while ((entry = jin.getNextJarEntry()) != null)
|
||||
{
|
||||
String entryName = entry.getName();
|
||||
|
||||
LOG.debug("Looking at {}", entryName);
|
||||
// make sure no access out of the root entry is present
|
||||
if (URIUtil.isNotNormalWithinSelf(entryName))
|
||||
{
|
||||
LOG.info("Invalid entry: {}", entryName);
|
||||
continue;
|
||||
}
|
||||
|
||||
Path file = directory.resolve(entryName);
|
||||
|
||||
if (entry.isDirectory())
|
||||
{
|
||||
if (isIncluded(entryName))
|
||||
{
|
||||
if (!isExcluded(entryName))
|
||||
{
|
||||
// Make directory
|
||||
if (!Files.exists(file))
|
||||
Files.createDirectories(file);
|
||||
}
|
||||
else
|
||||
LOG.debug("{} dir is excluded", entryName);
|
||||
}
|
||||
else
|
||||
LOG.debug("{} dir is NOT included", entryName);
|
||||
}
|
||||
else
|
||||
{
|
||||
//entry is a file, is it included?
|
||||
if (isIncluded(entryName))
|
||||
{
|
||||
if (!isExcluded(entryName))
|
||||
{
|
||||
// make directory (some jars don't list dirs)
|
||||
Path dir = file.getParent();
|
||||
if (!Files.exists(dir))
|
||||
Files.createDirectories(dir);
|
||||
|
||||
// Make file
|
||||
try (OutputStream fout = Files.newOutputStream(file))
|
||||
{
|
||||
IO.copy(jin, fout);
|
||||
}
|
||||
|
||||
// touch the file.
|
||||
if (entry.getTime() >= 0)
|
||||
Files.setLastModifiedTime(file, FileTime.fromMillis(entry.getTime()));
|
||||
}
|
||||
else
|
||||
LOG.debug("{} file is excluded", entryName);
|
||||
}
|
||||
else
|
||||
LOG.debug("{} file is NOT included", entryName);
|
||||
}
|
||||
}
|
||||
|
||||
Manifest manifest = jin.getManifest();
|
||||
if (manifest != null)
|
||||
{
|
||||
if (isIncluded("META-INF") && !isExcluded("META-INF"))
|
||||
{
|
||||
Path metaInf = directory.resolve("META-INF");
|
||||
Files.createDirectory(metaInf);
|
||||
Path f = metaInf.resolve("MANIFEST.MF");
|
||||
try (OutputStream fout = Files.newOutputStream(f))
|
||||
{
|
||||
manifest.write(fout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.nio.file.AtomicMoveNotSupportedException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle.AbstractLifeCycleListener;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
|
||||
/**
|
||||
* ServerConnectorListener
|
||||
*
|
||||
* This is for test support, where we need jetty to run on a random port, and we need
|
||||
* a client to be able to find out which port was picked.
|
||||
*/
|
||||
public class ServerConnectorListener extends AbstractLifeCycleListener
|
||||
{
|
||||
private String _fileName;
|
||||
private String _sysPropertyName;
|
||||
|
||||
@Override
|
||||
public void lifeCycleStarted(LifeCycle event)
|
||||
{
|
||||
if (getFileName() != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Path tmp = Files.createTempFile("jettyport", ".tmp");
|
||||
try (Writer writer = Files.newBufferedWriter(tmp))
|
||||
{
|
||||
writer.write(String.valueOf(((ServerConnector)event).getLocalPort()));
|
||||
}
|
||||
|
||||
Path path = Paths.get(getFileName());
|
||||
Files.deleteIfExists(path);
|
||||
try
|
||||
{
|
||||
Files.move(tmp, path, StandardCopyOption.ATOMIC_MOVE);
|
||||
}
|
||||
catch (AtomicMoveNotSupportedException e) // can append on some os (windows).. so try again without the option
|
||||
{
|
||||
Files.move(tmp, path);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (getSysPropertyName() != null)
|
||||
{
|
||||
System.setProperty(_sysPropertyName, String.valueOf(((ServerConnector)event).getLocalPort()));
|
||||
}
|
||||
super.lifeCycleStarted(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file name.
|
||||
* @return the file name
|
||||
*/
|
||||
public String getFileName()
|
||||
{
|
||||
return _fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the file name to set.
|
||||
* @param name the file name to set
|
||||
*/
|
||||
public void setFileName(String name)
|
||||
{
|
||||
|
||||
_fileName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sysPropertyName.
|
||||
* @return the sysPropertyName
|
||||
*/
|
||||
public String getSysPropertyName()
|
||||
{
|
||||
return _sysPropertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sysPropertyName to set.
|
||||
* @param sysPropertyName the sysPropertyName to set
|
||||
*/
|
||||
public void setSysPropertyName(String sysPropertyName)
|
||||
{
|
||||
_sysPropertyName = sysPropertyName;
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
|
||||
/**
|
||||
* ServerListener
|
||||
*
|
||||
* Listener to create a file that signals that the startup is completed.
|
||||
* Used by the JettyRunHome maven goal to determine that the child
|
||||
* process is started, and that jetty is ready.
|
||||
*/
|
||||
public class ServerListener implements LifeCycle.Listener
|
||||
{
|
||||
private String _tokenFile;
|
||||
|
||||
public void setTokenFile(String file)
|
||||
{
|
||||
_tokenFile = file;
|
||||
}
|
||||
|
||||
public String getTokenFile()
|
||||
{
|
||||
return _tokenFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lifeCycleStarted(LifeCycle event)
|
||||
{
|
||||
if (_tokenFile != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Using Path, as we need to reliably create/write a file.
|
||||
Path path = Path.of(_tokenFile);
|
||||
Files.createFile(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,236 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.ee10.webapp.Configurations;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.security.LoginService;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
|
||||
/**
|
||||
* ServerSupport
|
||||
*
|
||||
* Helps configure the Server instance.
|
||||
*/
|
||||
public class ServerSupport
|
||||
{
|
||||
|
||||
public static void configureDefaultConfigurationClasses(Server server)
|
||||
{
|
||||
Configurations.setServerDefault(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the handler structure to receive a webapp.
|
||||
* Also put in a DefaultHandler so we get a nicer page
|
||||
* than a 404 if we hit the root and the webapp's
|
||||
* context isn't at root.
|
||||
*
|
||||
* @param server the server to use
|
||||
* @param contextHandlers the context handlers to include
|
||||
* @param requestLog a request log to use
|
||||
*/
|
||||
public static void configureHandlers(Server server, List<ContextHandler> contextHandlers, RequestLog requestLog)
|
||||
{
|
||||
if (server == null)
|
||||
throw new IllegalArgumentException("Server is null");
|
||||
|
||||
if (requestLog != null)
|
||||
server.setRequestLog(requestLog);
|
||||
|
||||
ContextHandlerCollection contexts = findContextHandlerCollection(server);
|
||||
if (contexts == null)
|
||||
{
|
||||
contexts = new ContextHandlerCollection();
|
||||
server.setHandler(contexts);
|
||||
}
|
||||
|
||||
if (contextHandlers != null)
|
||||
{
|
||||
for (ContextHandler context:contextHandlers)
|
||||
{
|
||||
contexts.addHandler(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure at least one connector for the server
|
||||
*
|
||||
* @param server the server
|
||||
* @param connector the connector
|
||||
* @param properties jetty properties
|
||||
*/
|
||||
public static void configureConnectors(Server server, Connector connector, Map<String, String> properties)
|
||||
{
|
||||
if (server == null)
|
||||
throw new IllegalArgumentException("Server is null");
|
||||
|
||||
//if a connector is provided, use it
|
||||
if (connector != null)
|
||||
{
|
||||
server.addConnector(connector);
|
||||
return;
|
||||
}
|
||||
|
||||
// if the user hasn't configured the connectors in a jetty.xml file so use a default one
|
||||
Connector[] connectors = server.getConnectors();
|
||||
if (connectors == null || connectors.length == 0)
|
||||
{
|
||||
//Make a new default connector
|
||||
MavenServerConnector tmp = new MavenServerConnector();
|
||||
//use any jetty.http.port settings provided, trying system properties before jetty properties
|
||||
String port = System.getProperty(MavenServerConnector.PORT_SYSPROPERTY);
|
||||
if (port == null)
|
||||
port = System.getProperty("jetty.port");
|
||||
if (port == null)
|
||||
port = (properties != null ? properties.get(MavenServerConnector.PORT_SYSPROPERTY) : null);
|
||||
if (port == null)
|
||||
port = MavenServerConnector.DEFAULT_PORT_STR;
|
||||
tmp.setPort(Integer.parseInt(port.trim()));
|
||||
tmp.setServer(server);
|
||||
server.setConnectors(new Connector[]{tmp});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up any security LoginServices provided.
|
||||
*
|
||||
* @param server the server
|
||||
* @param loginServices the login services
|
||||
*/
|
||||
public static void configureLoginServices(Server server, List<LoginService> loginServices)
|
||||
{
|
||||
if (server == null)
|
||||
throw new IllegalArgumentException("Server is null");
|
||||
|
||||
if (loginServices != null)
|
||||
{
|
||||
for (LoginService loginService : loginServices)
|
||||
{
|
||||
PluginLog.getLog().debug(loginService.getClass().getName() + ": " + loginService.toString());
|
||||
server.addBean(loginService);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a WebAppContext to a Server
|
||||
* @param server the server to use
|
||||
* @param webapp the webapp to add
|
||||
*/
|
||||
public static void addWebApplication(Server server, WebAppContext webapp)
|
||||
{
|
||||
if (server == null)
|
||||
throw new IllegalArgumentException("Server is null");
|
||||
ContextHandlerCollection contexts = findContextHandlerCollection(server);
|
||||
if (contexts == null)
|
||||
throw new IllegalStateException("ContextHandlerCollection is null");
|
||||
contexts.addHandler(webapp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate a ContextHandlerCollection for a Server.
|
||||
*
|
||||
* @param server the Server to check.
|
||||
* @return The ContextHandlerCollection or null if not found.
|
||||
*/
|
||||
public static ContextHandlerCollection findContextHandlerCollection(Server server)
|
||||
{
|
||||
if (server == null)
|
||||
return null;
|
||||
|
||||
return server.getDescendant(ContextHandlerCollection.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply xml files to server instance.
|
||||
*
|
||||
* @param server the server to apply the xml to
|
||||
* @param files the list of xml files
|
||||
* @param properties list of jetty properties
|
||||
* @return the Server implementation, after the xml is applied
|
||||
* @throws Exception if unable to apply the xml configuration
|
||||
*/
|
||||
public static Server applyXmlConfigurations(Server server, List<File> files, Map<String, String> properties)
|
||||
throws Exception
|
||||
{
|
||||
if (files == null || files.isEmpty())
|
||||
return server;
|
||||
|
||||
Map<String, Object> lastMap = new HashMap<>();
|
||||
|
||||
if (server != null)
|
||||
lastMap.put("Server", server);
|
||||
|
||||
for (File xmlFile : files)
|
||||
{
|
||||
if (PluginLog.getLog() != null)
|
||||
PluginLog.getLog().info("Configuring Jetty from xml configuration file = " + xmlFile.getCanonicalPath());
|
||||
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(ResourceFactory.of(server).newResource(xmlFile.toPath()));
|
||||
|
||||
//add in any properties
|
||||
if (properties != null)
|
||||
{
|
||||
for (Map.Entry<String, String> e : properties.entrySet())
|
||||
{
|
||||
xmlConfiguration.getProperties().put(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
//chain ids from one config file to another
|
||||
if (lastMap != null)
|
||||
xmlConfiguration.getIdMap().putAll(lastMap);
|
||||
|
||||
//Set the system properties each time in case the config file set a new one
|
||||
Enumeration<?> ensysprop = System.getProperties().propertyNames();
|
||||
while (ensysprop.hasMoreElements())
|
||||
{
|
||||
String name = (String)ensysprop.nextElement();
|
||||
xmlConfiguration.getProperties().put(name, System.getProperty(name));
|
||||
}
|
||||
xmlConfiguration.configure();
|
||||
lastMap = xmlConfiguration.getIdMap();
|
||||
}
|
||||
|
||||
return (Server)lastMap.get("Server");
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply xml files to server instance.
|
||||
*
|
||||
* @param server the Server instance to configure
|
||||
* @param files the xml configs to apply
|
||||
* @return the Server after application of configs
|
||||
* @throws Exception if there is an unspecified problem
|
||||
*/
|
||||
public static Server applyXmlConfigurations(Server server, List<File> files)
|
||||
throws Exception
|
||||
{
|
||||
return applyXmlConfigurations(server, files, null);
|
||||
}
|
||||
}
|
|
@ -1,239 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.model.Plugin;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.codehaus.plexus.util.xml.Xpp3Dom;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
/**
|
||||
* WarPluginInfo
|
||||
*
|
||||
* Information about the maven-war-plugin contained in the pom
|
||||
*/
|
||||
public class WarPluginInfo
|
||||
{
|
||||
private MavenProject _project;
|
||||
private Plugin _plugin;
|
||||
private List<String> _dependentMavenWarIncludes;
|
||||
private List<String> _dependentMavenWarExcludes;
|
||||
private List<OverlayConfig> _overlayConfigs;
|
||||
private Set<Artifact> _warArtifacts;
|
||||
|
||||
public WarPluginInfo(MavenProject project)
|
||||
{
|
||||
_project = project;
|
||||
if (_project.getArtifacts() != null)
|
||||
{
|
||||
_warArtifacts = _project.getArtifacts()
|
||||
.stream()
|
||||
.filter(a -> "war".equals(a.getType()) || "zip".equals(a.getType())).collect(Collectors.toSet());
|
||||
}
|
||||
else
|
||||
_warArtifacts = Collections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the project.
|
||||
* @return the project
|
||||
*/
|
||||
public MavenProject getProject()
|
||||
{
|
||||
return _project;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all dependent artifacts that are wars.
|
||||
* @return all artifacts of type "war" or "zip"
|
||||
*/
|
||||
public Set<Artifact> getWarArtifacts()
|
||||
{
|
||||
return _warArtifacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an artifact of type war that matches the given coordinates.
|
||||
* @param groupId the groupId to match
|
||||
* @param artifactId the artifactId to match
|
||||
* @param classifier the classified to match
|
||||
* @return the matching Artifact or null if no match
|
||||
*/
|
||||
public Artifact getWarArtifact(String groupId, String artifactId, String classifier)
|
||||
{
|
||||
Optional<Artifact> o = _warArtifacts.stream()
|
||||
.filter(a -> match(a, groupId, artifactId, classifier)).findFirst();
|
||||
return o.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the maven-war-plugin, if one is configured
|
||||
*
|
||||
* @return the plugin
|
||||
*/
|
||||
public Plugin getWarPlugin()
|
||||
{
|
||||
if (_plugin == null)
|
||||
{
|
||||
List<Plugin> plugins = _project.getBuildPlugins();
|
||||
if (plugins == null)
|
||||
return null;
|
||||
|
||||
for (Plugin p : plugins)
|
||||
{
|
||||
if ("maven-war-plugin".equals(p.getArtifactId()))
|
||||
{
|
||||
_plugin = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value of dependentWarIncludes for maven-war-plugin
|
||||
*
|
||||
* @return the list of dependent war includes
|
||||
*/
|
||||
public List<String> getDependentMavenWarIncludes()
|
||||
{
|
||||
if (_dependentMavenWarIncludes == null)
|
||||
{
|
||||
getWarPlugin();
|
||||
|
||||
if (_plugin == null)
|
||||
return null;
|
||||
|
||||
Xpp3Dom node = (Xpp3Dom)_plugin.getConfiguration();
|
||||
if (node == null)
|
||||
return null;
|
||||
|
||||
node = node.getChild("dependentWarIncludes");
|
||||
if (node == null)
|
||||
return null;
|
||||
String val = node.getValue();
|
||||
_dependentMavenWarIncludes = StringUtil.csvSplit(null, val, 0, val.length());
|
||||
}
|
||||
return _dependentMavenWarIncludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value of dependentWarExcludes for maven-war-plugin
|
||||
*
|
||||
* @return the list of dependent war excludes
|
||||
*/
|
||||
public List<String> getDependentMavenWarExcludes()
|
||||
{
|
||||
if (_dependentMavenWarExcludes == null)
|
||||
{
|
||||
getWarPlugin();
|
||||
|
||||
if (_plugin == null)
|
||||
return null;
|
||||
|
||||
Xpp3Dom node = (Xpp3Dom)_plugin.getConfiguration();
|
||||
if (node == null)
|
||||
return null;
|
||||
|
||||
node = node.getChild("dependentWarExcludes");
|
||||
if (node == null)
|
||||
return null;
|
||||
String val = node.getValue();
|
||||
_dependentMavenWarExcludes = StringUtil.csvSplit(null, val, 0, val.length());
|
||||
}
|
||||
return _dependentMavenWarExcludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get config for any overlays that have been declared for the maven-war-plugin.
|
||||
*
|
||||
* @return the list of overlay configs
|
||||
*/
|
||||
public List<OverlayConfig> getMavenWarOverlayConfigs()
|
||||
{
|
||||
if (_overlayConfigs == null)
|
||||
{
|
||||
getWarPlugin();
|
||||
|
||||
if (_plugin == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
getDependentMavenWarIncludes();
|
||||
getDependentMavenWarExcludes();
|
||||
|
||||
Xpp3Dom node = (Xpp3Dom)_plugin.getConfiguration();
|
||||
if (node == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
node = node.getChild("overlays");
|
||||
if (node == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
Xpp3Dom[] nodes = node.getChildren("overlay");
|
||||
if (nodes == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
_overlayConfigs = new ArrayList<OverlayConfig>();
|
||||
for (int i = 0; i < nodes.length; i++)
|
||||
{
|
||||
OverlayConfig overlayConfig = new OverlayConfig(nodes[i], _dependentMavenWarIncludes, _dependentMavenWarExcludes);
|
||||
_overlayConfigs.add(overlayConfig);
|
||||
}
|
||||
}
|
||||
|
||||
return _overlayConfigs;
|
||||
}
|
||||
|
||||
public boolean match(Artifact a, String gid, String aid, String cls)
|
||||
{
|
||||
if (a == null)
|
||||
return (gid == null && aid == null && cls == null);
|
||||
|
||||
if (((a.getGroupId() == null && gid == null) || (a.getGroupId() != null && a.getGroupId().equals(gid))) &&
|
||||
((a.getArtifactId() == null && aid == null) || (a.getArtifactId() != null && a.getArtifactId().equals(aid))) &&
|
||||
((a.getClassifier() == null) || (a.getClassifier().equals(cls))))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given artifact matches the group and artifact coordinates.
|
||||
*
|
||||
* @param a the artifact to check
|
||||
* @param gid the group id
|
||||
* @param aid the artifact id
|
||||
* @return true if matched false otherwise
|
||||
*/
|
||||
public boolean match(Artifact a, String gid, String aid)
|
||||
{
|
||||
if (a == null)
|
||||
return (gid == null && aid == null);
|
||||
|
||||
if (((a.getGroupId() == null && gid == null) || (a.getGroupId() != null && a.getGroupId().equals(gid))) &&
|
||||
((a.getArtifactId() == null && aid == null) || (a.getArtifactId() != null && a.getArtifactId().equals(aid))))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,185 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.ee10.maven.plugin.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.maven.RepositoryUtils;
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.artifact.repository.ArtifactRepository;
|
||||
import org.apache.maven.execution.MavenSession;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.eclipse.aether.RepositorySystem;
|
||||
import org.eclipse.aether.artifact.DefaultArtifact;
|
||||
import org.eclipse.aether.resolution.ArtifactRequest;
|
||||
import org.eclipse.aether.resolution.ArtifactResolutionException;
|
||||
import org.eclipse.aether.resolution.ArtifactResult;
|
||||
import org.eclipse.jetty.ee10.maven.plugin.OverlayManager;
|
||||
import org.eclipse.jetty.ee10.maven.plugin.WarPluginInfo;
|
||||
|
||||
/**
|
||||
* MavenProjectHelper
|
||||
*
|
||||
* A class to facilitate interacting with the build time maven environment.
|
||||
*/
|
||||
public class MavenProjectHelper
|
||||
{
|
||||
private MavenProject project;
|
||||
private RepositorySystem repositorySystem;
|
||||
private List<ArtifactRepository> remoteRepositories;
|
||||
private MavenSession session;
|
||||
private final Map<String, MavenProject> artifactToReactorProjectMap;
|
||||
/**
|
||||
* maven-war-plugin reference
|
||||
*/
|
||||
private WarPluginInfo warPluginInfo;
|
||||
|
||||
/**
|
||||
* Helper for wrangling war overlays
|
||||
*/
|
||||
private OverlayManager overlayManager;
|
||||
|
||||
/**
|
||||
* @param project the project being built
|
||||
* @param repositorySystem a resolve for artifacts
|
||||
* @param remoteRepositories repositories from which to resolve artifacts
|
||||
* @param session the current maven build session
|
||||
*/
|
||||
public MavenProjectHelper(MavenProject project, RepositorySystem repositorySystem, List<ArtifactRepository> remoteRepositories, MavenSession session)
|
||||
{
|
||||
this.project = project;
|
||||
this.repositorySystem = repositorySystem;
|
||||
this.remoteRepositories = remoteRepositories;
|
||||
this.session = session;
|
||||
//work out which dependent projects are in the reactor
|
||||
Set<MavenProject> mavenProjects = findDependenciesInReactor(project, new HashSet<>());
|
||||
artifactToReactorProjectMap = mavenProjects.stream()
|
||||
.collect(Collectors.toMap(MavenProject::getId, Function.identity()));
|
||||
artifactToReactorProjectMap.put(project.getArtifact().getId(), project);
|
||||
warPluginInfo = new WarPluginInfo(project);
|
||||
overlayManager = new OverlayManager(warPluginInfo);
|
||||
}
|
||||
|
||||
public MavenProject getProject()
|
||||
{
|
||||
return this.project;
|
||||
}
|
||||
|
||||
public WarPluginInfo getWarPluginInfo()
|
||||
{
|
||||
return warPluginInfo;
|
||||
}
|
||||
|
||||
public OverlayManager getOverlayManager()
|
||||
{
|
||||
return overlayManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maven project represented by the artifact iff it is in
|
||||
* the reactor.
|
||||
*
|
||||
* @param artifact the artifact of the project to get
|
||||
* @return {@link MavenProject} if artifact is referenced in reactor, otherwise null
|
||||
*/
|
||||
public MavenProject getMavenProjectFor(Artifact artifact)
|
||||
{
|
||||
if (artifact == null)
|
||||
return null;
|
||||
return artifactToReactorProjectMap.get(artifact.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets path to artifact.
|
||||
* If the artifact is referenced in the reactor, returns path to ${project.build.outputDirectory}.
|
||||
* Otherwise, returns path to location in local m2 repo.
|
||||
*
|
||||
* Cannot return null - maven will complain about unsatisfied dependency during project build.
|
||||
*
|
||||
* @param artifact maven artifact to check
|
||||
* @return path to artifact
|
||||
*/
|
||||
public Path getPathFor(Artifact artifact)
|
||||
{
|
||||
Path path = artifact.getFile().toPath();
|
||||
MavenProject mavenProject = getMavenProjectFor(artifact);
|
||||
if (mavenProject != null)
|
||||
{
|
||||
if ("test-jar".equals(artifact.getType()))
|
||||
{
|
||||
path = Paths.get(mavenProject.getBuild().getTestOutputDirectory());
|
||||
}
|
||||
else
|
||||
{
|
||||
path = Paths.get(mavenProject.getBuild().getOutputDirectory());
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the coordinates for an artifact, resolve the artifact from the
|
||||
* remote repositories.
|
||||
*
|
||||
* @param groupId the groupId of the artifact to resolve
|
||||
* @param artifactId the artifactId of the artifact to resolve
|
||||
* @param version the version of the artifact to resolve
|
||||
* @param type the type of the artifact to resolve
|
||||
* @return a File representing the location of the artifact or null if not resolved
|
||||
*/
|
||||
public File resolveArtifact(String groupId, String artifactId, String version, String type)
|
||||
throws ArtifactResolutionException
|
||||
{
|
||||
ArtifactRequest request = new ArtifactRequest();
|
||||
request.setRepositories(RepositoryUtils.toRepos(remoteRepositories));
|
||||
request.setArtifact(new DefaultArtifact(groupId, artifactId, "", type, version));
|
||||
ArtifactResult result = repositorySystem.resolveArtifact(session.getRepositorySession(), request);
|
||||
|
||||
if (result.isResolved())
|
||||
return result.getArtifact().getFile();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively find projects in the reactor for all dependencies of the given project.
|
||||
*
|
||||
* @param project the project for which to find dependencies that are in the reactor
|
||||
* @param visitedProjects the set of projects already seen
|
||||
* @return unified set of all related projects in the reactor
|
||||
*/
|
||||
private static Set<MavenProject> findDependenciesInReactor(MavenProject project, Set<MavenProject> visitedProjects)
|
||||
{
|
||||
if (visitedProjects.contains(project))
|
||||
return Collections.emptySet();
|
||||
|
||||
visitedProjects.add(project);
|
||||
Collection<MavenProject> refs = project.getProjectReferences().values();
|
||||
Set<MavenProject> availableProjects = new HashSet<>(refs);
|
||||
for (MavenProject ref : refs)
|
||||
{
|
||||
availableProjects.addAll(findDependenciesInReactor(ref, visitedProjects));
|
||||
}
|
||||
return availableProjects;
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ ee10-webapp
|
|||
ee10-annotations
|
||||
|
||||
[lib]
|
||||
lib/maven-ee10/*.jar
|
||||
lib/ee10-maven/*.jar
|
||||
|
||||
[xml]
|
||||
etc/jetty-ee10-maven.xml
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee10.maven.plugin.ServerListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerListener">
|
||||
<Set name="tokenFile"><Property name="jetty.token.file"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -88,7 +88,7 @@ public class TestForkedChild
|
|||
webapp.setBaseResourceAsPath(baseDir.toPath());
|
||||
WebAppPropertyConverter.toProperties(webapp, webappPropsFile, null);
|
||||
child = new JettyForkedChild(cmd.toArray(new String[0]));
|
||||
child.jetty.setExitVm(false); //ensure jetty doesn't stop vm for testing
|
||||
child.getJettyEmbedder().setExitVm(false); //ensure jetty doesn't stop vm for testing
|
||||
child.start();
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
@ -19,6 +19,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.ee10.servlet.ListenerHolder;
|
||||
import org.eclipse.jetty.maven.MavenServerConnector;
|
||||
import org.eclipse.jetty.maven.ServerSupport;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
|
@ -119,7 +121,7 @@ public class TestJettyEmbedder
|
|||
assertTrue(contexts.contains(webApp));
|
||||
|
||||
//stop the webapp and check durable listener retained
|
||||
jetty.getWebApp().stop();
|
||||
jetty.stopWebApp();
|
||||
boolean someListener = false;
|
||||
for (ListenerHolder h : webApp.getServletHandler().getListeners())
|
||||
{
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.nio.file.Path;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.maven.SelectiveJarResource;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
|
|
|
@ -279,7 +279,9 @@ public class ServletChannel
|
|||
public ServletContextResponse getServletContextResponse()
|
||||
{
|
||||
ServletContextRequest request = _servletContextRequest;
|
||||
return request == null ? null : request.getServletContextResponse();
|
||||
if (_servletContextRequest == null)
|
||||
throw new IllegalStateException("Request/Response does not exist (likely recycled)");
|
||||
return request.getServletContextResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -291,6 +293,8 @@ public class ServletChannel
|
|||
*/
|
||||
public Response getResponse()
|
||||
{
|
||||
if (_response == null)
|
||||
throw new IllegalStateException("Response does not exist (likely recycled)");
|
||||
return _response;
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ import org.eclipse.jetty.server.Handler;
|
|||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.server.ResponseUtils;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
|
@ -103,6 +104,7 @@ import static org.hamcrest.Matchers.contains;
|
|||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
|
@ -692,6 +694,31 @@ public class ServletContextHandlerTest
|
|||
_server.join();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnsureNotPersistent() throws Exception
|
||||
{
|
||||
ServletContextHandler root = new ServletContextHandler("/", ServletContextHandler.SESSIONS);
|
||||
root.setContextPath("/");
|
||||
root.addServlet(new ServletHolder(new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
{
|
||||
Request request = ((ServletApiRequest)req).getRequest();
|
||||
Response response = ((ServletApiResponse)resp).getResponse();
|
||||
|
||||
ResponseUtils.ensureNotPersistent(request, response);
|
||||
}
|
||||
}), "/ensureNotPersistent");
|
||||
_server.setHandler(root);
|
||||
|
||||
_server.start();
|
||||
|
||||
String rawResponse = _connector.getResponse("GET /ensureNotPersistent HTTP/1.0\r\n\r\n");
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
assertThat(response.getStatus(), is(200));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitParams() throws Exception
|
||||
{
|
||||
|
|
|
@ -200,7 +200,7 @@ public class CreationTest
|
|||
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
|
||||
|
||||
//check that the session does not exist
|
||||
assertFalse(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore().exists(servlet._id));
|
||||
Awaitility.waitAtMost(5, TimeUnit.SECONDS).until(() -> !contextHandler.getSessionHandler().getSessionCache().getSessionDataStore().exists(servlet._id));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -245,7 +245,7 @@ public class CreationTest
|
|||
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
|
||||
|
||||
//check that the session does not exist
|
||||
assertFalse(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore().exists(servlet._id));
|
||||
Awaitility.waitAtMost(5, TimeUnit.SECONDS).until(() -> !contextHandler.getSessionHandler().getSessionCache().getSessionDataStore().exists(servlet._id));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -287,8 +287,8 @@ public class CreationTest
|
|||
ContentResponse response = client.GET(url);
|
||||
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
|
||||
|
||||
//check that the session does not exist
|
||||
assertTrue(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore().exists(servlet._id));
|
||||
//check the session
|
||||
Awaitility.waitAtMost(5, TimeUnit.SECONDS).until(() -> contextHandler.getSessionHandler().getSessionCache().getSessionDataStore().exists(servlet._id));
|
||||
assertThat(response.getHeaders().getValuesList(HttpHeader.SET_COOKIE).size(), Matchers.is(1));
|
||||
}
|
||||
finally
|
||||
|
@ -338,8 +338,8 @@ public class CreationTest
|
|||
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
|
||||
|
||||
//check that the sessions exist persisted
|
||||
assertTrue(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore().exists(servlet._id));
|
||||
assertTrue(ctxB.getSessionHandler().getSessionCache().getSessionDataStore().exists(servlet._id));
|
||||
Awaitility.waitAtMost(5, TimeUnit.SECONDS).until(() -> contextHandler.getSessionHandler().getSessionCache().getSessionDataStore().exists(servlet._id));
|
||||
Awaitility.waitAtMost(5, TimeUnit.SECONDS).until(() -> ctxB.getSessionHandler().getSessionCache().getSessionDataStore().exists(servlet._id));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -387,9 +387,9 @@ public class CreationTest
|
|||
ContentResponse response = client.GET(url + "?action=forwardinv");
|
||||
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
|
||||
|
||||
//check that the session does not exist
|
||||
assertFalse(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore().exists(servlet._id));
|
||||
assertFalse(ctxB.getSessionHandler().getSessionCache().getSessionDataStore().exists(servlet._id));
|
||||
//check that the session does not exist
|
||||
Awaitility.waitAtMost(5, TimeUnit.SECONDS).until(() -> !contextHandler.getSessionHandler().getSessionCache().getSessionDataStore().exists(servlet._id));
|
||||
Awaitility.waitAtMost(5, TimeUnit.SECONDS).until(() -> !ctxB.getSessionHandler().getSessionCache().getSessionDataStore().exists(servlet._id));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -77,6 +77,7 @@ public class AttributeNameTest
|
|||
|
||||
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
|
||||
cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT);
|
||||
cacheFactory.setSaveOnCreate(true);
|
||||
|
||||
MongoSessionDataStoreFactory storeFactory = MongoTestHelper.newSessionDataStoreFactory(DB_NAME, COLLECTION_NAME);
|
||||
storeFactory.setGracePeriodSec(scavengePeriod);
|
||||
|
|
|
@ -86,6 +86,10 @@
|
|||
<artifactId>jetty-jndi</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-maven</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee8.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee8.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee8.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<Ref refid="httpConnector">
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee8.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee8.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee8.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
|
@ -140,7 +140,7 @@
|
|||
</jettyXmls>
|
||||
<loginServices>
|
||||
<loginService implementation="org.eclipse.jetty.security.HashLoginService">
|
||||
<config implementation="org.eclipse.jetty.ee8.maven.plugin.MavenResource">
|
||||
<config implementation="org.eclipse.jetty.maven.MavenResource">
|
||||
<resourceAsString>${basedir}/src/config/login.xml</resourceAsString>
|
||||
</config>
|
||||
</loginService>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</Arg>
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.ee8.maven.plugin.ServerConnectorListener">
|
||||
<New class="org.eclipse.jetty.maven.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue