diff --git a/Jenkinsfile b/Jenkinsfile index 20a937eb1fe..d24aac9ba18 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -41,8 +41,9 @@ def getFullBuild(jdk, os) { maven: 'maven3', jdk: "$jdk", publisherStrategy: 'EXPLICIT', + globalMavenSettingsConfig: 'oss-settings.xml', mavenLocalRepo: "${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}") { - sh "mvn -V -B clean install -Dtest=None -T6" + sh "mvn -V -B clean install -DskipTests -T6" } } @@ -62,6 +63,7 @@ def getFullBuild(jdk, os) { maven: 'maven3', jdk: "$jdk", publisherStrategy: 'EXPLICIT', + globalMavenSettingsConfig: 'oss-settings.xml', mavenLocalRepo: "${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}") { sh "mvn -V -B javadoc:javadoc -T5" } @@ -83,6 +85,8 @@ def getFullBuild(jdk, os) { maven: 'maven3', jdk: "$jdk", publisherStrategy: 'EXPLICIT', + //options: [invokerPublisher(disabled: false)], + globalMavenSettingsConfig: 'oss-settings.xml', mavenLocalRepo: "${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}") { // sh "mvn -V -B install -Dmaven.test.failure.ignore=true -Prun-its -T3 -e -Dmaven.repo.local=${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}" @@ -137,6 +141,7 @@ def getFullBuild(jdk, os) { maven: 'maven3', jdk: "$jdk", publisherStrategy: 'EXPLICIT', + globalMavenSettingsConfig: 'oss-settings.xml', mavenLocalRepo: "${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}") { sh "mvn -V -B -Pcompact3 clean install -T5" } diff --git a/VERSION.txt b/VERSION.txt index ed7bee002cf..5fb540da654 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1,5 +1,97 @@ jetty-10.0.0-SNAPSHOT +jetty-9.4.9.v20180320 - 20 March 2018 + + 347 Avoid sending request using a connection that is idle timing out + + 1416 GzipHandler generated ETag suffix has problems with If-Match header + logic + + 1602 WebAppContext is started twice, once by deployer, again by lifecycle + + 1614 AbstractNCSARequestLog does not extract the user from the http header + when it has not been authenticated + + 1770 SniX509ExtendedKeyManager.chooseServerAlias() throws + NullPointerException when socket is null + + 1797 JEP 238 - Multi-Release JAR files break bytecode scanning + + 1832 Bad HTTP Close prevents proper TCP close + + 1918 Scalable scheduler implementation + + 1933 Use CLASSPATH for scanning java9 system classes + + 1940 Embedded CDI: SessionScoped gives a NPE + + 1949 Client-side problems with digest authentication + + 1956 Store and report build information of Jetty + + 1966 HttpMethod case sensitive + + 1970 ManagedSelector can lose selector thread under high concurrent load + + 1973 Implement minimum response data rate + + 1983 Improve warning for incompatible ALPN processor + + 1986 ServletContextHandler.Context addListener() methods support + session listeners + + 2003 Do not submit blocking tasks as managed selector actions + + 2006 ServletInputStream.isReady not registering interest when it should + + 2010 SniX509ExtendedKeyManager causes exception: "FIPS mode: only SunJSSE + KeyManagers may be used" + + 2014 Support unix domain sockets in HttpClient + + 2015 jetty-alpn-conscrypt-server needs appropriate osgi headers in manifest + + 2016 jetty-alpn-openjdk8-server needs correct osgi headers in manifest + + 2019 Expose HttpClientTransport in JMX + + 2020 Introduce a name for `HttpClient` instances + + 2022 Fine grained RFC HTTP Compliance modes: including OWS prior to field + colon + + 2028 Add osgi headers for alpn-java client and server + + 2030 NPE in AnnotationConfiguration with DEBUG enabled + + 2033 Improve HTTP/2 session and stream stall times report + + 2034 Improve HTTP2Session dump + + 2035 FlowControlStrategy keeps around reset streams + + 2037 HTTP/2 stream reset leaves stream frames in the flusher + + 2038 FileSessionDataStore.deleteAllFiles(File, String) can become slow + + 2043 ConcurrentModificationException during annotation parsing + + 2046 Server.stop not closing connections + + 2050 Clarify ObjectMBean getObject[Name|Context]Basis() methods + + 2079 Upgrade to apache jasper 8.5.24 + + 2080 Exclude more maven machinery dependencies from the jetty-maven-plugin + server path + + 2081 No idle timeout exception when dispatch is delayed + + 2088 Recycle HTTP/2 channels on the client + + 2090 Jetty fails to start on OpenJDK 9: "Invalid Java version 9.0.1.3" + + 2093 Correcting Bom managed dependencies that do not exist + + 2114 Fix NPE in JettyHttpServerProvider + + 2117 Allow to configure HttpClient default request Content-Type + + 2130 Introduce thread pool module for simpler configuration of thread pool + in standalone + + 2131 Introduce a monitored thread pool + + 2136 maven & jetty-maven-plugin & offline + error:java.net.UnknownHostException: www.eclipse.org + + 2148 Limit BufferUtil.toDetailString() raw character display to USASCII + 7-bit printable characters + + 2152 Produce jetty-home-source artifacts for Eclipse Jetty source jars + + 2160 Digest authentication should use absolute path + + 2164 Ensure all jetty modules that use ServiceLoader have correct OSGi + manifest headers + + 2190 HTTP/2 close and GOAWAY behavior + + 2203 Use GlobalWebAppConfigBinding rather than special methods on + DeploymentManager/WebAppProvider + + 2209 jetty-maven-plugin deploy-war silently fails (unless the pom has war + packaging) + + 2210 NPE at org.eclipse.jetty.client.HttpDestination.newExchangeQueue + + 2218 Adding workaround for Windows NIO Selector Bug + + 2232 Dependency Conflict: Conflicting JARs org.apache.maven:maven-project + + 2255 Notify SSL handshake failures on write failures + + 2275 jetty.server.ResourceService.doGet() + RequestDispatcher INCLUDE + + 2278 Could not find artifact + org.eclipse.jetty.tests:test-webapps-parent:pom:9.4.8.v20171121 + + 2279 Jetty 9.4.x start.jar: "?=" in [ini] defeats Issue #1139 functionality + + 2280 Default application/json to utf-8 encoding in encoding.properties + + 2284 NPE from start.jar during JVM version parsing + + 2288 Cleanup the statistics classes + + 2291 Expose HTTP/2 close reason in dumps + + 2293 HTTP/2 client multiplexed connection pool creates too many connections + + 2297 HTTP/2 client transport should honor HttpClient.connectBlocking + + 2298 Override the processor number with an environment variable + + 2307 Error page can have null charset in content type + + 2308 Type change in MonitorTask - int cannot be converted to + ThreadPoolExecutor + + 2312 HTTP/2 Connection.Listener notified after first request + + 2313 Dump HTTP/2 channel state + + 2318 HttpParser.Listener.onBadMessage() should take BadMessageException + + 2346 Missing stack traces in HTTPChannel.onException + + 2358 Add ALPN module file for JDK 10 + jetty-9.4.8.v20171121 - 21 November 2017 + 212 HttpClient should support pluggable AuthenticationStore + 215 Add Conscrypt for native ALPN/TLS/SSL diff --git a/apache-jsp/src/main/config/modules/apache-jsp.mod b/apache-jsp/src/main/config/modules/apache-jsp.mod index 5fa57f7c85c..62ea32b33c0 100644 --- a/apache-jsp/src/main/config/modules/apache-jsp.mod +++ b/apache-jsp/src/main/config/modules/apache-jsp.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables use of the apache implementation of JSP diff --git a/apache-jstl/src/main/config/modules/apache-jstl.mod b/apache-jstl/src/main/config/modules/apache-jstl.mod index 37e6f7757f5..55c89366ade 100644 --- a/apache-jstl/src/main/config/modules/apache-jstl.mod +++ b/apache-jstl/src/main/config/modules/apache-jstl.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables the apache version of JSTL diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl.mod index d726e163d24..181d668a67d 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Selects an ALPN (Application Layer Protocol Negotiation) implementation by java version. diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0.mod index 91fea30cd0e..bbcca55ad48 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_05.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_05.mod index 91fea30cd0e..bbcca55ad48 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_05.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_05.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_101.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_101.mod index eebd2a92550..d940468a7ff 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_101.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_101.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.9.v20160720/alpn-boot-8.1.9.v20160720.jar|lib/alpn/alpn-boot-8.1.9.v20160720.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_102.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_102.mod index eebd2a92550..d940468a7ff 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_102.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_102.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.9.v20160720/alpn-boot-8.1.9.v20160720.jar|lib/alpn/alpn-boot-8.1.9.v20160720.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_11.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_11.mod index 91fea30cd0e..bbcca55ad48 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_11.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_11.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_111.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_111.mod index eebd2a92550..d940468a7ff 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_111.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_111.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.9.v20160720/alpn-boot-8.1.9.v20160720.jar|lib/alpn/alpn-boot-8.1.9.v20160720.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_112.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_112.mod index 3887113d09b..e244e3bed3d 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_112.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_112.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.10.v20161026/alpn-boot-8.1.10.v20161026.jar|lib/alpn/alpn-boot-8.1.10.v20161026.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_121.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_121.mod index eb50f520252..6afa18151a4 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_121.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_121.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar|lib/alpn/alpn-boot-8.1.11.v20170118.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_131.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_131.mod index eb50f520252..6afa18151a4 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_131.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_131.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar|lib/alpn/alpn-boot-8.1.11.v20170118.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_141.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_141.mod index eb50f520252..6afa18151a4 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_141.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_141.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar|lib/alpn/alpn-boot-8.1.11.v20170118.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_144.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_144.mod index eb50f520252..6afa18151a4 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_144.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_144.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar|lib/alpn/alpn-boot-8.1.11.v20170118.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_151.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_151.mod index eb50f520252..6afa18151a4 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_151.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_151.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar|lib/alpn/alpn-boot-8.1.11.v20170118.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_152.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_152.mod index eb50f520252..6afa18151a4 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_152.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_152.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar|lib/alpn/alpn-boot-8.1.11.v20170118.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_161.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_161.mod index b50a352334d..e2e91808cd3 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_161.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_161.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.12.v20180117/alpn-boot-8.1.12.v20180117.jar|lib/alpn/alpn-boot-8.1.12.v20180117.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_162.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_162.mod index b50a352334d..e2e91808cd3 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_162.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_162.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.12.v20180117/alpn-boot-8.1.12.v20180117.jar|lib/alpn/alpn-boot-8.1.12.v20180117.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_20.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_20.mod index 91fea30cd0e..bbcca55ad48 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_20.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_20.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_25.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_25.mod index 55f736902df..f34b1841244 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_25.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_25.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] maven://org.mortbay.jetty.alpn/alpn-boot/8.1.2.v20141202|lib/alpn/alpn-boot-8.1.2.v20141202.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_31.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_31.mod index 030029db54d..9ffca1a9699 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_31.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_31.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] maven://org.mortbay.jetty.alpn/alpn-boot/8.1.3.v20150130|lib/alpn/alpn-boot-8.1.3.v20150130.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_40.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_40.mod index ebd06d4dda6..3d5c1aeb044 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_40.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_40.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.3.v20150130/alpn-boot-8.1.3.v20150130.jar|lib/alpn/alpn-boot-8.1.3.v20150130.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_45.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_45.mod index ebd06d4dda6..3d5c1aeb044 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_45.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_45.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.3.v20150130/alpn-boot-8.1.3.v20150130.jar|lib/alpn/alpn-boot-8.1.3.v20150130.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_51.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_51.mod index a0472beca95..51a8dbb518d 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_51.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_51.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.4.v20150727/alpn-boot-8.1.4.v20150727.jar|lib/alpn/alpn-boot-8.1.4.v20150727.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_60.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_60.mod index 0751b15b093..4f639da61a1 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_60.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_60.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.5.v20150921/alpn-boot-8.1.5.v20150921.jar|lib/alpn/alpn-boot-8.1.5.v20150921.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_65.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_65.mod index 32ae03ea282..80d1541775d 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_65.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_65.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.6.v20151105/alpn-boot-8.1.6.v20151105.jar|lib/alpn/alpn-boot-8.1.6.v20151105.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_66.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_66.mod index 32ae03ea282..80d1541775d 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_66.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_66.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.6.v20151105/alpn-boot-8.1.6.v20151105.jar|lib/alpn/alpn-boot-8.1.6.v20151105.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_71.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_71.mod index 47bc2df34c1..bf0de731394 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_71.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_71.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_72.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_72.mod index 47bc2df34c1..bf0de731394 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_72.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_72.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_73.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_73.mod index 47bc2df34c1..bf0de731394 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_73.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_73.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_74.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_74.mod index 47bc2df34c1..bf0de731394 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_74.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_74.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_77.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_77.mod index 47bc2df34c1..bf0de731394 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_77.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_77.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_91.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_91.mod index 47bc2df34c1..bf0de731394 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_91.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_91.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_92.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_92.mod index 10d83db2181..267aa41ea37 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_92.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_92.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [files] http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.8.v20160420/alpn-boot-8.1.8.v20160420.jar|lib/alpn/alpn-boot-8.1.8.v20160420.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-10.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-10.mod new file mode 100644 index 00000000000..689601a4197 --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-10.mod @@ -0,0 +1,4 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[depend] +alpn-impl/alpn-9 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-11.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-11.mod new file mode 100644 index 00000000000..689601a4197 --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-11.mod @@ -0,0 +1,4 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[depend] +alpn-impl/alpn-9 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-8.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-8.mod index 6ace07a2e6b..84454089e27 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-8.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-8.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Provides ALPN support for JDK 8, modifying the sun.security.ssl classes and adding them to the JVM boot classpath. diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-9.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-9.mod index 9a2708ba89a..e1de6726af9 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-9.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-9.mod @@ -1,5 +1,7 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] -Provides support for ALPN based on JDK 9 APIs. +Provides support for ALPN based on JDK 9+ APIs. [lib] lib/jetty-alpn-java-server-${jetty.version}.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn.mod index cb02222ed89..a245331f71f 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables the ALPN (Application Layer Protocol Negotiation) TLS extension. diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_144.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_144.mod deleted file mode 100644 index fdd3868701d..00000000000 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_144.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar|lib/alpn/alpn-boot-8.1.11.v20170118.jar - -[exec] --Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar diff --git a/jetty-annotations/src/main/config/modules/annotations.mod b/jetty-annotations/src/main/config/modules/annotations.mod index 585a1501565..7bbe6db7480 100644 --- a/jetty-annotations/src/main/config/modules/annotations.mod +++ b/jetty-annotations/src/main/config/modules/annotations.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables Annotation scanning for deployed webapplications. diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index 4140a535333..b7849daf331 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -48,6 +48,7 @@ import org.eclipse.jetty.plus.annotation.ContainerInitializer; import org.eclipse.jetty.plus.webapp.PlusConfiguration; import org.eclipse.jetty.util.JavaVersion; import org.eclipse.jetty.util.MultiException; +import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; @@ -467,7 +468,7 @@ public class AnnotationConfiguration extends AbstractConfiguration start = System.nanoTime(); //execute scan, either effectively synchronously (1 thread only), or asynchronously (limited by number of processors available) - final Semaphore task_limit = (isUseMultiThreading(context)? new Semaphore(Runtime.getRuntime().availableProcessors()):new Semaphore(1)); + final Semaphore task_limit = (isUseMultiThreading(context)? new Semaphore(ProcessorUtils.availableProcessors()):new Semaphore( 1)); final CountDownLatch latch = new CountDownLatch(_parserTasks.size()); final MultiException me = new MultiException(); diff --git a/jetty-cdi/cdi-2/src/main/config/modules/cdi2.mod b/jetty-cdi/cdi-2/src/main/config/modules/cdi2.mod index 48717ecb930..11896dbbfd7 100644 --- a/jetty-cdi/cdi-2/src/main/config/modules/cdi2.mod +++ b/jetty-cdi/cdi-2/src/main/config/modules/cdi2.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Jetty setup to support Weld/CDI2 with WELD inside the webapp diff --git a/jetty-client/src/main/config/modules/client.mod b/jetty-client/src/main/config/modules/client.mod index e9d13c8c689..ccc1d50db83 100644 --- a/jetty-client/src/main/config/modules/client.mod +++ b/jetty-client/src/main/config/modules/client.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Adds the Jetty HTTP client to the server classpath. diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectionPool.java index 65f6454eceb..19ec8ba7bf8 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectionPool.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectionPool.java @@ -20,10 +20,10 @@ package org.eclipse.jetty.client; import java.util.Collection; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.api.Destination; +import org.eclipse.jetty.util.AtomicBiInteger; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.annotation.ManagedAttribute; @@ -39,7 +39,12 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable private static final Logger LOG = Log.getLogger(AbstractConnectionPool.class); private final AtomicBoolean closed = new AtomicBoolean(); - private final AtomicInteger connectionCount = new AtomicInteger(); + + /** + * The connectionCount encodes both the total connections plus the pending connection counts, so both can be atomically changed. + * The bottom 32 bits represent the total connections and the top 32 bits represent the pending connections. + */ + private final AtomicBiInteger connections = new AtomicBiInteger(); private final Destination destination; private final int maxConnections; private final Callback requester; @@ -60,13 +65,19 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable @ManagedAttribute(value = "The number of connections", readonly = true) public int getConnectionCount() { - return connectionCount.get(); + return connections.getLo(); + } + + @ManagedAttribute(value = "The number of pending connections", readonly = true) + public int getPendingCount() + { + return connections.getHi(); } @Override public boolean isEmpty() { - return connectionCount.get() == 0; + return connections.getLo() == 0; } @Override @@ -80,29 +91,34 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable { Connection connection = activate(); if (connection == null) - connection = tryCreate(); + { + tryCreate(-1); + connection = activate(); + } return connection; } - private Connection tryCreate() + protected void tryCreate(int maxPending) { while (true) { - int current = getConnectionCount(); - final int next = current + 1; + long encoded = connections.get(); + int pending = AtomicBiInteger.getHi(encoded); + int total = AtomicBiInteger.getLo(encoded); - if (next > maxConnections) + if (LOG.isDebugEnabled()) + LOG.debug("tryCreate {}/{} connections {}/{} pending",total,maxConnections,pending,maxPending); + + if (total >= maxConnections) + return; + + if (maxPending>=0 && pending>=maxPending) + return; + + if (connections.compareAndSet(encoded,pending+1,total+1)) { if (LOG.isDebugEnabled()) - LOG.debug("Max connections {}/{} reached", current, maxConnections); - // Try again the idle connections - return activate(); - } - - if (connectionCount.compareAndSet(current, next)) - { - if (LOG.isDebugEnabled()) - LOG.debug("Connection {}/{} creation", next, maxConnections); + LOG.debug("newConnection {}/{} connections {}/{} pending", total+1, maxConnections, pending+1, maxPending); destination.newConnection(new Promise() { @@ -110,7 +126,8 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable public void succeeded(Connection connection) { if (LOG.isDebugEnabled()) - LOG.debug("Connection {}/{} creation succeeded {}", next, maxConnections, connection); + LOG.debug("Connection {}/{} creation succeeded {}", total+1, maxConnections, connection); + connections.update(-1,0); onCreated(connection); proceed(); } @@ -119,14 +136,13 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable public void failed(Throwable x) { if (LOG.isDebugEnabled()) - LOG.debug("Connection " + next + "/" + maxConnections + " creation failed", x); - connectionCount.decrementAndGet(); + LOG.debug("Connection " + (total+1) + "/" + maxConnections + " creation failed", x); + connections.update(-1,-1); requester.failed(x); } }); - // Try again the idle connections - return activate(); + return; } } } @@ -174,7 +190,7 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable protected void removed(Connection connection) { - int pooled = connectionCount.decrementAndGet(); + int pooled = connections.updateLo(-1); if (LOG.isDebugEnabled()) LOG.debug("Connection removed {} - pooled: {}", connection, pooled); } @@ -184,7 +200,7 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable { if (closed.compareAndSet(false, true)) { - connectionCount.set(0); + connections.set(0,0); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectorHttpClientTransport.java b/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectorHttpClientTransport.java index 4644c08a03e..669ba41d757 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectorHttpClientTransport.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectorHttpClientTransport.java @@ -88,20 +88,21 @@ public abstract class AbstractConnectorHttpClientTransport extends AbstractHttpC context.put(SslClientConnectionFactory.SSL_PEER_HOST_CONTEXT_KEY, destination.getHost()); context.put(SslClientConnectionFactory.SSL_PEER_PORT_CONTEXT_KEY, destination.getPort()); + boolean connected = true; if (client.isConnectBlocking()) { channel.socket().connect(address, (int)client.getConnectTimeout()); channel.configureBlocking(false); - selectorManager.accept(channel, context); } else { channel.configureBlocking(false); - if (channel.connect(address)) - selectorManager.accept(channel, context); - else - selectorManager.connect(channel, context); + connected = channel.connect(address); } + if (connected) + selectorManager.accept(channel, context); + else + selectorManager.connect(channel, context); } // Must catch all exceptions, since some like // UnresolvedAddressException are not IOExceptions. diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java index 57aa3d66917..d2895b64fd8 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java @@ -91,4 +91,20 @@ public interface ConnectionPool extends Closeable */ ConnectionPool newConnectionPool(HttpDestination destination); } + + /** + * Marks a connection pool as supporting multiplexed connections. + */ + interface Multiplexable + { + /** + * @return the max number of requests multiplexable on a single connection + */ + int getMaxMultiplex(); + + /** + * @param maxMultiplex the max number of requests multiplexable on a single connection + */ + void setMaxMultiplex(int maxMultiplex); + } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java index 6d7f84b5304..37230b902ec 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java @@ -70,10 +70,14 @@ public abstract class HttpChannel } if (abort) + { exchange.getRequest().abort(new UnsupportedOperationException("Pipelined requests not supported")); - - if (LOG.isDebugEnabled()) - LOG.debug("{} associated {} to {}", exchange, result, this); + } + else + { + if (LOG.isDebugEnabled()) + LOG.debug("{} associated {} to {}", exchange, result, this); + } return result; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java index cdbea4365fc..53620d78bde 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java @@ -64,6 +64,7 @@ import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Jetty; +import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.SocketAddressResolver; import org.eclipse.jetty.util.annotation.ManagedAttribute; @@ -213,7 +214,7 @@ public class HttpClient extends ContainerLifeCycle byteBufferPool = new MappedByteBufferPool(2048, executor instanceof ThreadPool.SizedThreadPool ? ((ThreadPool.SizedThreadPool)executor).getMaxThreads()/2 - : Runtime.getRuntime().availableProcessors()*2); + : ProcessorUtils.availableProcessors()*2); addBean(byteBufferPool); if (scheduler == null) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java index 544bbadc23f..0f02a6d970d 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java @@ -81,6 +81,17 @@ public class HttpContent implements Callback, Closeable this.iterator = provider == null ? Collections.emptyIterator() : provider.iterator(); } + /** + * @param buffer + * @return true if the buffer is the sentinel instance {@link CLOSE} + */ + private static boolean isTheCloseBuffer(ByteBuffer buffer) + { + @SuppressWarnings("ReferenceEquality") + boolean isTheCloseBuffer = (buffer == CLOSE); + return isTheCloseBuffer; + } + /** * @return whether there is any content at all */ @@ -177,6 +188,7 @@ public class HttpContent implements Callback, Closeable /** * @return whether the cursor has been advanced past the {@link #isLast() last} position. */ + @SuppressWarnings("ReferenceEquality") public boolean isConsumed() { return buffer == AFTER; @@ -187,7 +199,7 @@ public class HttpContent implements Callback, Closeable { if (isConsumed()) return; - if (buffer == CLOSE) + if (isTheCloseBuffer(buffer)) return; if (iterator instanceof Callback) ((Callback)iterator).succeeded(); @@ -198,7 +210,7 @@ public class HttpContent implements Callback, Closeable { if (isConsumed()) return; - if (buffer == CLOSE) + if (isTheCloseBuffer(buffer)) return; if (iterator instanceof Callback) ((Callback)iterator).failed(x); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java index be229cda4c9..7ae3fbb56d2 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java @@ -204,7 +204,10 @@ public class HttpRequest implements Request { if (uri == null) uri = buildURI(true); - return uri == NULL_URI ? null : uri; + + @SuppressWarnings("ReferenceEquality") + boolean isNullURI = (uri == NULL_URI); + return isNullURI ? null : uri; } @Override diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexConnectionPool.java index e26aacb8c37..179d66e9ca3 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexConnectionPool.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexConnectionPool.java @@ -36,11 +36,12 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Sweeper; -public class MultiplexConnectionPool extends AbstractConnectionPool implements Sweeper.Sweepable +public class MultiplexConnectionPool extends AbstractConnectionPool implements ConnectionPool.Multiplexable, Sweeper.Sweepable { private static final Logger LOG = Log.getLogger(MultiplexConnectionPool.class); private final ReentrantLock lock = new ReentrantLock(); + private final HttpDestination destination; private final Deque idleConnections; private final Map muxedConnections; private final Map busyConnections; @@ -49,12 +50,26 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements S public MultiplexConnectionPool(HttpDestination destination, int maxConnections, Callback requester, int maxMultiplex) { super(destination, maxConnections, requester); + this.destination = destination; this.idleConnections = new ArrayDeque<>(maxConnections); this.muxedConnections = new HashMap<>(maxConnections); this.busyConnections = new HashMap<>(maxConnections); this.maxMultiplex = maxMultiplex; } + @Override + public Connection acquire() + { + Connection connection = activate(); + if (connection == null) + { + int maxPending = 1 + destination.getQueuedRequestCount() / getMaxMultiplex(); + tryCreate(maxPending); + connection = activate(); + } + return connection; + } + protected void lock() { lock.lock(); @@ -65,6 +80,7 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements S lock.unlock(); } + @Override public int getMaxMultiplex() { lock(); @@ -78,6 +94,7 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements S } } + @Override public void setMaxMultiplex(int maxMultiplex) { lock(); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java index ee1ceb30cca..44c264a36cf 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java @@ -28,15 +28,15 @@ public abstract class MultiplexHttpDestination extends HttpDestination public int getMaxRequestsPerConnection() { ConnectionPool connectionPool = getConnectionPool(); - if (connectionPool instanceof MultiplexConnectionPool) - return ((MultiplexConnectionPool)connectionPool).getMaxMultiplex(); + if (connectionPool instanceof ConnectionPool.Multiplexable) + return ((ConnectionPool.Multiplexable)connectionPool).getMaxMultiplex(); return 1; } public void setMaxRequestsPerConnection(int maxRequestsPerConnection) { ConnectionPool connectionPool = getConnectionPool(); - if (connectionPool instanceof MultiplexConnectionPool) - ((MultiplexConnectionPool)connectionPool).setMaxMultiplex(maxRequestsPerConnection); + if (connectionPool instanceof ConnectionPool.Multiplexable) + ((ConnectionPool.Multiplexable)connectionPool).setMaxMultiplex(maxRequestsPerConnection); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/RoundRobinConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/RoundRobinConnectionPool.java index b33929254f7..f69cbf63eea 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/RoundRobinConnectionPool.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/RoundRobinConnectionPool.java @@ -29,17 +29,42 @@ import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.component.ContainerLifeCycle; @ManagedObject -public class RoundRobinConnectionPool extends AbstractConnectionPool +public class RoundRobinConnectionPool extends AbstractConnectionPool implements ConnectionPool.Multiplexable { private final List entries; + private int maxMultiplex; private int index; public RoundRobinConnectionPool(Destination destination, int maxConnections, Callback requester) + { + this(destination, maxConnections, requester, 1); + } + + public RoundRobinConnectionPool(Destination destination, int maxConnections, Callback requester, int maxMultiplex) { super(destination, maxConnections, requester); entries = new ArrayList<>(maxConnections); for (int i = 0; i < maxConnections; ++i) entries.add(new Entry()); + this.maxMultiplex = maxMultiplex; + } + + @Override + public int getMaxMultiplex() + { + synchronized (this) + { + return maxMultiplex; + } + } + + @Override + public void setMaxMultiplex(int maxMultiplex) + { + synchronized (this) + { + this.maxMultiplex = maxMultiplex; + } } @Override @@ -78,10 +103,10 @@ public class RoundRobinConnectionPool extends AbstractConnectionPool if (entry.connection == null) break; - if (!entry.active) + if (entry.active < getMaxMultiplex()) { - entry.active = true; - entry.used++; + ++entry.active; + ++entry.used; connection = entry.connection; index += offset + 1; if (index >= capacity) @@ -103,7 +128,7 @@ public class RoundRobinConnectionPool extends AbstractConnectionPool for (Entry entry : entries) { if (entry.connection == connection) - return entry.active; + return entry.active > 0; } return false; } @@ -112,56 +137,60 @@ public class RoundRobinConnectionPool extends AbstractConnectionPool @Override public boolean release(Connection connection) { - boolean active = false; + boolean found = false; + boolean idle = false; synchronized (this) { for (Entry entry : entries) { if (entry.connection == connection) { - entry.active = false; - active = true; + found = true; + int active = --entry.active; + idle = active == 0; break; } } } - if (active) - released(connection); - return idle(connection, isClosed()); + if (!found) + return false; + released(connection); + if (idle) + return idle(connection, isClosed()); + return true; } @Override public boolean remove(Connection connection) { - boolean active = false; - boolean removed = false; + boolean found = false; synchronized (this) { for (Entry entry : entries) { if (entry.connection == connection) { - active = entry.active; + found = true; entry.reset(); - removed = true; break; } } } - if (active) + if (found) + { released(connection); - if (removed) removed(connection); - return removed; + } + return found; } @Override public void dump(Appendable out, String indent) throws IOException { - List connections = new ArrayList<>(); + List connections; synchronized (this) { - connections.addAll(entries); + connections = new ArrayList<>(entries); } ContainerLifeCycle.dumpObject(out, this); ContainerLifeCycle.dump(out, indent, connections); @@ -179,7 +208,7 @@ public class RoundRobinConnectionPool extends AbstractConnectionPool if (entry.connection != null) { ++present; - if (entry.active) + if (entry.active > 0) ++active; } } @@ -196,13 +225,13 @@ public class RoundRobinConnectionPool extends AbstractConnectionPool private static class Entry { private Connection connection; - private boolean active; + private int active; private long used; private void reset() { connection = null; - active = false; + active = 0; used = 0; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpClientTransportOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpClientTransportOverHTTP.java index da25e45cedf..d91bc1da02a 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpClientTransportOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpClientTransportOverHTTP.java @@ -27,6 +27,7 @@ import org.eclipse.jetty.client.HttpDestination; import org.eclipse.jetty.client.Origin; import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.annotation.ManagedObject; @@ -35,7 +36,7 @@ public class HttpClientTransportOverHTTP extends AbstractConnectorHttpClientTran { public HttpClientTransportOverHTTP() { - this(Math.max(1, Runtime.getRuntime().availableProcessors() / 2)); + this(Math.max( 1, ProcessorUtils.availableProcessors() / 2)); } public HttpClientTransportOverHTTP(int selectors) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java index b211ed32574..bdae896e13b 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java @@ -26,7 +26,7 @@ import org.eclipse.jetty.client.HttpExchange; import org.eclipse.jetty.client.HttpReceiver; import org.eclipse.jetty.client.HttpResponse; import org.eclipse.jetty.client.HttpResponseException; -import org.eclipse.jetty.http.HttpCompliance; +import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpParser; @@ -42,6 +42,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res private final HttpParser parser; private ByteBuffer buffer; private boolean shutdown; + private boolean complete; public HttpReceiverOverHTTP(HttpChannelOverHTTP channel) { @@ -168,13 +169,22 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res { while (true) { - // Must parse even if the buffer is fully consumed, to allow the - // parser to advance from asynchronous content to response complete. boolean handle = parser.parseNext(buffer); + boolean complete = this.complete; + this.complete = false; if (LOG.isDebugEnabled()) LOG.debug("Parsed {}, remaining {} {}", handle, buffer.remaining(), parser); - if (handle || !buffer.hasRemaining()) - return handle; + if (handle) + return true; + if (!buffer.hasRemaining()) + return false; + if (complete) + { + if (LOG.isDebugEnabled()) + LOG.debug("Discarding unexpected content after response: {}", BufferUtil.toDetailString(buffer)); + BufferUtil.clear(buffer); + return false; + } } } @@ -298,11 +308,15 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res if (exchange == null) return false; + int status = exchange.getResponse().getStatus(); + + if (status != HttpStatus.CONTINUE_100) + complete = true; + boolean proceed = responseSuccess(exchange); if (!proceed) return true; - int status = exchange.getResponse().getStatus(); if (status == HttpStatus.SWITCHING_PROTOCOLS_101) return true; @@ -325,13 +339,13 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res } @Override - public void badMessage(int status, String reason) + public void badMessage(BadMessageException failure) { HttpExchange exchange = getHttpExchange(); if (exchange != null) { HttpResponse response = exchange.getResponse(); - response.status(status).reason(reason); + response.status(failure.getCode()).reason(failure.getReason()); failAndClose(new HttpResponseException("HTTP protocol violation: bad response on " + getHttpConnection(), response)); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java index e80163c81b8..003d685f9c6 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java @@ -321,10 +321,10 @@ public class HttpSenderOverHTTP extends HttpSender private void release() { ByteBufferPool bufferPool = httpClient.getByteBufferPool(); - if (headerBuffer != BufferUtil.EMPTY_BUFFER) + if (!BufferUtil.isTheEmptyBuffer(headerBuffer)) bufferPool.release(headerBuffer); headerBuffer = null; - if (chunkBuffer != BufferUtil.EMPTY_BUFFER) + if (!BufferUtil.isTheEmptyBuffer(chunkBuffer)) bufferPool.release(chunkBuffer); chunkBuffer = null; contentBuffer = null; diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java index 96fd6cc27ec..3dd0d4a1c99 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java @@ -589,6 +589,7 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest public ByteBuffer current; @Override + @SuppressWarnings("ReferenceEquality") public boolean hasNext() { if (current == null) diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java index e5bcef5e9ed..a363f90438f 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java @@ -18,8 +18,6 @@ package org.eclipse.jetty.client; -import static org.junit.Assert.assertThat; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -1297,8 +1295,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest } catch(ExecutionException e) { - assertThat(e.getCause(), Matchers.instanceOf(BadMessageException.class)); - assertThat(e.getCause().getMessage(), Matchers.containsString("Unknown content")); + Assert.assertThat(e.getCause(), Matchers.instanceOf(BadMessageException.class)); + Assert.assertThat(e.getCause().getMessage(), Matchers.containsString("Unknown content")); } } @@ -1311,8 +1309,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest } catch(ExecutionException e) { - assertThat(e.getCause(), Matchers.instanceOf(BadMessageException.class)); - assertThat(e.getCause().getMessage(), Matchers.containsString("Unknown content")); + Assert.assertThat(e.getCause(), Matchers.instanceOf(BadMessageException.class)); + Assert.assertThat(e.getCause().getMessage(), Matchers.containsString("Unknown content")); } } @@ -1650,6 +1648,70 @@ public class HttpClientTest extends AbstractHttpClientServerTest Assert.assertEquals(200, response.getStatus()); } + @Test + public void test204WithContent() throws Exception + { + // This test only works with clear-text HTTP. + Assume.assumeTrue(sslContextFactory == null); + + try (ServerSocket server = new ServerSocket(0)) + { + startClient(); + client.setMaxConnectionsPerDestination(1); + int idleTimeout = 2000; + client.setIdleTimeout(idleTimeout); + + Request request = client.newRequest("localhost", server.getLocalPort()) + .scheme(scheme) + .timeout(5, TimeUnit.SECONDS); + FutureResponseListener listener = new FutureResponseListener(request); + request.send(listener); + + try (Socket socket = server.accept()) + { + socket.setSoTimeout(idleTimeout / 2); + + InputStream input = socket.getInputStream(); + consume(input, false); + + // Send a bad response. + String httpResponse = "" + + "HTTP/1.1 204 No Content\r\n" + + "\r\n" + + "No Content"; + OutputStream output = socket.getOutputStream(); + output.write(httpResponse.getBytes(StandardCharsets.UTF_8)); + output.flush(); + + ContentResponse response = listener.get(5, TimeUnit.SECONDS); + Assert.assertEquals(204, response.getStatus()); + + byte[] responseContent = response.getContent(); + Assert.assertNotNull(responseContent); + Assert.assertEquals(0, responseContent.length); + + // Send another request to verify we have handled the wrong response correctly. + request = client.newRequest("localhost", server.getLocalPort()) + .scheme(scheme) + .timeout(5, TimeUnit.SECONDS); + listener = new FutureResponseListener(request); + request.send(listener); + + consume(input, false); + + httpResponse = "" + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 0\r\n" + + "\r\n"; + output.write(httpResponse.getBytes(StandardCharsets.UTF_8)); + output.flush(); + + response = listener.get(5, TimeUnit.SECONDS); + Assert.assertEquals(200, response.getStatus()); + } + } + } + private void assertCopyRequest(Request original) { Request copy = client.copyRequest((HttpRequest) original, original.getURI()); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/LivelockTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/LivelockTest.java index 448dd426d16..aa359c69b80 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/LivelockTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/LivelockTest.java @@ -19,6 +19,8 @@ package org.eclipse.jetty.client; import java.nio.channels.Selector; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -30,14 +32,37 @@ import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.util.SocketAddressResolver; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +@RunWith(Parameterized.class) public class LivelockTest { + @Parameterized.Parameters(name = "server={0}, client={1}") + public static List data() + { + List data = new ArrayList<>(); + // Server-live-lock, Client-live-lock + data.add(new Object[] { true, true }); + data.add(new Object[] { true, false }); + data.add(new Object[] { false, true }); + data.add(new Object[] { false, false }); + return data; + } + + @Parameterized.Parameter(0) + public boolean serverLiveLock; + + @Parameterized.Parameter(1) + public boolean clientLiveLock; + private Server server; private ServerConnector connector; private HttpClient client; @@ -73,7 +98,7 @@ public class LivelockTest // ManagedSelectors that submit themselves in an attempt to cause a live lock // as there will always be an action available to run. - int count = 25; + int count = 5; HttpClientTransport transport = new HttpClientTransportOverHTTP(1); client = new HttpClient(transport, null); client.setMaxConnectionsPerDestination(2 * count); @@ -88,34 +113,21 @@ public class LivelockTest AtomicBoolean busy = new AtomicBoolean(true); - ManagedSelector clientSelector = client.getContainedBeans(ManagedSelector.class).stream().findAny().get(); - ManagedSelector.SelectorUpdate clientLivelock = new ManagedSelector.SelectorUpdate() + if (clientLiveLock) { - @Override - public void update(Selector selector) - { - sleep(10); - if (busy.get()) - clientSelector.submit(this); - } - }; - clientSelector.submit(clientLivelock); - - ManagedSelector serverSelector = connector.getContainedBeans(ManagedSelector.class).stream().findAny().get(); - ManagedSelector.SelectorUpdate serverLivelock = new ManagedSelector.SelectorUpdate() + ManagedSelector clientSelector = client.getContainedBeans(ManagedSelector.class).stream().findAny().get(); + busyLiveLock(busy, clientSelector); + } + + if (serverLiveLock) { - @Override - public void update(Selector selector) - { - sleep(10); - if (busy.get()) - serverSelector.submit(this); - } - }; - serverSelector.submit(serverLivelock); + ManagedSelector serverSelector = connector.getContainedBeans(ManagedSelector.class).stream().findAny().get(); + busyLiveLock(busy, serverSelector); + } int requestRate = 5; long pause = 1000 / requestRate; + Logger clientLog = Log.getLogger("TESTClient"); CountDownLatch latch = new CountDownLatch(count); for (int i = 0; i < count; ++i) { @@ -125,6 +137,13 @@ public class LivelockTest { if (result.isSucceeded() && result.getResponse().getStatus() == HttpStatus.OK_200) latch.countDown(); + else + { + if(result.getRequestFailure() != null) + clientLog.warn(result.getRequestFailure()); + if(result.getResponseFailure() != null) + clientLog.warn(result.getResponseFailure()); + } }); sleep(pause); } @@ -134,11 +153,26 @@ public class LivelockTest busy.set(false); } - private void sleep(long time) + private void busyLiveLock(AtomicBoolean busy, ManagedSelector managedSelector) + { + ManagedSelector.SelectorUpdate liveLock = new ManagedSelector.SelectorUpdate() + { + @Override + public void update(Selector selector) + { + sleep(10); + if (busy.get()) + managedSelector.submit(this); + } + }; + managedSelector.submit(liveLock); + } + + private void sleep(long millis) { try { - Thread.sleep(time); + TimeUnit.MILLISECONDS.sleep(millis); } catch (InterruptedException x) { diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/RoundRobinConnectionPoolTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/RoundRobinConnectionPoolTest.java deleted file mode 100644 index ac8a1ea9a25..00000000000 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/RoundRobinConnectionPoolTest.java +++ /dev/null @@ -1,99 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.client; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.hamcrest.Matchers; -import org.junit.Assert; -import org.junit.Test; - -public class RoundRobinConnectionPoolTest extends AbstractHttpClientServerTest -{ - public RoundRobinConnectionPoolTest(SslContextFactory sslContextFactory) - { - super(sslContextFactory); - } - - @Test - public void testRoundRobin() throws Exception - { - AtomicBoolean record = new AtomicBoolean(); - List remotePorts = new ArrayList<>(); - start(new EmptyServerHandler() - { - @Override - protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - if (record.get()) - remotePorts.add(request.getRemotePort()); - } - }); - - int maxConnections = 3; - client.getTransport().setConnectionPoolFactory(destination -> new RoundRobinConnectionPool(destination, maxConnections, destination)); - - // Prime the connections, so that they are all opened - // before we actually test the round robin behavior. - String host = "localhost"; - int port = connector.getLocalPort(); - for (int i = 0; i < maxConnections; ++i) - { - ContentResponse response = client.newRequest(host, port) - .scheme(scheme) - .timeout(5, TimeUnit.SECONDS) - .send(); - Assert.assertEquals(HttpStatus.OK_200, response.getStatus()); - } - - record.set(true); - int requests = 2 * maxConnections - 1; - for (int i = 0; i < requests; ++i) - { - ContentResponse response = client.newRequest(host, port) - .scheme(scheme) - .timeout(5, TimeUnit.SECONDS) - .send(); - Assert.assertEquals(HttpStatus.OK_200, response.getStatus()); - } - - Assert.assertThat(remotePorts.size(), Matchers.equalTo(requests)); - for (int i = 0; i < requests; ++i) - { - int base = i % maxConnections; - int expected = remotePorts.get(base); - int candidate = remotePorts.get(i); - Assert.assertThat(client.dump() + System.lineSeparator() + remotePorts.toString(), expected, Matchers.equalTo(candidate)); - if (i > 0) - Assert.assertThat(remotePorts.get(i - 1), Matchers.not(Matchers.equalTo(candidate))); - } - } -} diff --git a/jetty-client/src/test/resources/jetty-logging.properties b/jetty-client/src/test/resources/jetty-logging.properties index a2296dfdf69..3f7f23333ae 100644 --- a/jetty-client/src/test/resources/jetty-logging.properties +++ b/jetty-client/src/test/resources/jetty-logging.properties @@ -1,5 +1,5 @@ -org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -#org.eclipse.jetty.LEVEL=DEBUG +class=org.eclipse.jetty.util.log.StdErrLog +#org.eclipse.jetty.LEVEL=INFO #org.eclipse.jetty.client.LEVEL=DEBUG #org.eclipse.jetty.io.ChannelEndPoint.LEVEL=DEBUG #org.eclipse.jetty.http.LEVEL=DEBUG diff --git a/jetty-deploy/src/main/config/modules/deploy.mod b/jetty-deploy/src/main/config/modules/deploy.mod index 737e24f2e5d..6321ae50496 100644 --- a/jetty-deploy/src/main/config/modules/deploy.mod +++ b/jetty-deploy/src/main/config/modules/deploy.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables webapplication deployment from the webapps directory. diff --git a/jetty-deploy/src/main/config/modules/global-webapp-common.d/global-webapp-common.xml b/jetty-deploy/src/main/config/modules/global-webapp-common.d/global-webapp-common.xml index 5eee32ec2ac..aa3d308bbf7 100644 --- a/jetty-deploy/src/main/config/modules/global-webapp-common.d/global-webapp-common.xml +++ b/jetty-deploy/src/main/config/modules/global-webapp-common.d/global-webapp-common.xml @@ -1,5 +1,5 @@ - + diff --git a/jetty-deploy/src/main/config/modules/global-webapp-common.mod b/jetty-deploy/src/main/config/modules/global-webapp-common.mod index 2785fef3c8c..59b7386f05a 100644 --- a/jetty-deploy/src/main/config/modules/global-webapp-common.mod +++ b/jetty-deploy/src/main/config/modules/global-webapp-common.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables Deployer to apply common configuration to all webapp deployments diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java index ac5541aede7..50f320f5b76 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; @@ -311,10 +312,12 @@ public class DeploymentManager extends ContainerLifeCycle */ public Collection getApps(Node node) { + Objects.requireNonNull(node); + List ret = new ArrayList<>(); for (AppEntry entry : _apps) { - if (entry.lifecyleNode == node) + if (node.equals(entry.lifecyleNode)) { ret.add(entry.app); } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Edge.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Edge.java index 024e25c5a26..83fec32fcc4 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Edge.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Edge.java @@ -28,7 +28,9 @@ public final class Edge public Edge(Node from, Node to) { - if (from==null || to==null || from==to) + @SuppressWarnings("ReferenceEquality") + boolean sameObject = (from==to); + if (from==null || to==null || sameObject) throw new IllegalArgumentException("from "+from+" to "+to); _from = from; _to = to; @@ -71,7 +73,7 @@ public final class Edge { return _from; } - + public Node getTo() { return _to; diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Graph.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Graph.java index c0aba65f542..a0fe24a7c95 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Graph.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Graph.java @@ -40,7 +40,7 @@ public class Graph addNode(toNode=edge.getTo()); // replace edge with normalized edge - if (edge.getFrom()!=fromNode || edge.getTo()!=toNode) + if (!edge.getFrom().equals(fromNode) || !edge.getTo().equals(toNode)) edge=new Edge(fromNode,toNode); this._edges.add(edge); @@ -129,7 +129,7 @@ public class Graph for (Edge edge : this._edges) { - if ((edge.getFrom() == node) || (edge.getTo() == node)) + if (edge.getFrom().equals(node) || edge.getTo().equals(node)) { fromedges.add(edge); } @@ -151,7 +151,7 @@ public class Graph for (Edge edge : this._edges) { - if (edge.getFrom() == from) + if (edge.getFrom().equals(from)) { fromedges.add(edge); } @@ -192,7 +192,9 @@ public class Graph */ public Path getPath(Node from, Node to) { - if (from == to) + @SuppressWarnings("ReferenceEquality") + boolean sameObject = (from==to); + if (sameObject) { return new Path(); } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/jmx/DeploymentManagerMBean.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/jmx/DeploymentManagerMBean.java index 3c0ea08de81..165d10a122a 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/jmx/DeploymentManagerMBean.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/jmx/DeploymentManagerMBean.java @@ -74,7 +74,7 @@ public class DeploymentManagerMBean extends ObjectMBean List ret = new ArrayList<>(); for (DeploymentManager.AppEntry entry : _manager.getAppEntries()) { - if (entry.getLifecyleNode() == node) + if (node.equals(entry.getLifecyleNode())) { ret.add(toRef(entry.getApp())); } diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/screen-empty-base-listconfig.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/screen-empty-base-listconfig.adoc index 113f785ded3..712487db306 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/screen-empty-base-listconfig.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/screen-empty-base-listconfig.adoc @@ -59,10 +59,6 @@ System Properties: Properties: ----------- java.version = 1.8.0_92 - java.version.major = 1 - java.version.minor = 8 - java.version.revision = 0 - java.version.update = 92 Jetty Server Classpath: ----------------------- diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/screen-http-webapp-deploy-listconfig.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/screen-http-webapp-deploy-listconfig.adoc index 4b38f264772..b63440dda76 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/screen-http-webapp-deploy-listconfig.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/screen-http-webapp-deploy-listconfig.adoc @@ -59,10 +59,6 @@ System Properties: Properties: ----------- java.version = 1.8.0_92 - java.version.major = 1 - java.version.minor = 8 - java.version.revision = 0 - java.version.update = 92 Jetty Server Classpath: ----------------------- diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/startup-modules.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/startup-modules.adoc index e198222ee56..ee2ff06ebe3 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/startup-modules.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/startup-modules.adoc @@ -148,6 +148,14 @@ This is done by editing the associated ini file for the module. If your server setup is using a centralized ini configuration, you will edit the `${jetty.base}/server.ini` file. If you have elected to manage each module within it's own ini file, you can find these files in the `${jetty.base}/start.d` directory. +____ +[IMPORTANT] +It is important that you *do not* modify the module files in the `$JETTY_HOME/modules` directory. +$JETTY_HOME should always remain a standard of truth. +If you want to make a change to an actual module file (not the values in its `ini-template`), either edit its associated `ini` file in the `$JETTY_BASE/start.d` directory or make a copy of the desired module file and copy it to the `$JETTY_BASE` directory and edit it there. +The start.jar reads local `$JETTY_BASE/modules` files (if they exist) before scanning `$JETTY_HOME`. +____ + When a module is activated, a number of properties are set by default. To view these defaults, open up the associated ini file. Listed in the ini file is the associated module file and any properties that can be set. diff --git a/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc b/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc index 14534ce8886..41408190c55 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc @@ -719,10 +719,10 @@ This is _not_ a recommended usage. ____ [[conscrypt]] -===== Conscrypt SSL +==== Conscrypt SSL -Jetty also includes support for Google's https://github.com/google/conscrypt/[Conscrypt SSL], which is built on their fork of https://www.openssl.org/[OpenSSL], https://boringssl.googlesource.com/boringssl/[BoringSSL]. -Implementing Conscrypt is very straightforward process - simply instantiate an instance of Conscrypt's `OpenSSLProvider` and set `Conscrypt` as a provider for Jetty's `SslContextFactory`: +Jetty includes support for Google's https://github.com/google/conscrypt/[Conscrypt SSL], which is built on their fork of https://www.openssl.org/[OpenSSL], https://boringssl.googlesource.com/boringssl/[BoringSSL]. +Implementing Conscrypt for the link:{GITBROWSEURL}/jetty-alpn/jetty-alpn-conscrypt-server/src/test/java/org/eclipse/jetty/alpn/conscrypt/server/ConscryptHTTP2Server.java[server] or link:{GITBROWSEURL}/jetty-alpn/jetty-alpn-conscrypt-client/src/test/java/org/eclipse/jetty/alpn/java/client/ConscryptHTTP2Client.java[client] is very straightforward process - simply instantiate an instance of Conscrypt's `OpenSSLProvider` and set `Conscrypt` as a provider for Jetty's `SslContextFactory`: [source, java, subs="{sub-order}"] ---- diff --git a/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-authentication.adoc b/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-authentication.adoc index 52c7b224bf4..fa954e06721 100644 --- a/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-authentication.adoc +++ b/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-authentication.adoc @@ -75,6 +75,17 @@ URI uri = URI.create("http://domain.com/secure"); auth.addAuthenticationResult(new BasicAuthentication.BasicResult(uri, "username", "password")); ---- -In this way, the original request is enriched by `HttpClient` immediately with the `Authorization` header, and the server should respond with a 200 and the resource content rather than with the 401 and the challenge. +In this way, requests for the given URI are enriched by `HttpClient` immediately with the `Authorization` header, and the server should respond with a 200 and the resource content rather than with the 401 and the challenge. + +It is also possible to preempt the authentication for a single request only, in this way: + +[source, java, subs="{sub-order}"] +---- +URI uri = URI.create("http://domain.com/secure"); +Authentication.Result authn = new BasicAuthentication.BasicResult(uri, "username", "password") +Request request = httpClient.newRequest(uri); +authn.apply(request); +request.send(); +---- See also the link:#http-client-proxy-authentication[proxy authentication section] for further information about how authentication works with HTTP proxies. diff --git a/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-version.adoc b/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-version.adoc index a14335c1845..52902ec03c8 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-version.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-version.adoc @@ -35,7 +35,7 @@ _____ |Version |Year |Home |JVM |Protocols |Servlet |JSP |Status |9.4 |2016- |Eclipse |1.8 |HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |3.1 |2.3 |Stable |9.3 |2015- |Eclipse |1.8 |HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |3.1 |2.3 |Stable -|9.2 |2014- |Eclipse |1.7 |HTTP/1.1 RFC2616, javax.websocket, SPDY v3 |3.1 |2.3 |Deprecated / *End of Life January 2018* +|9.2 |2014-2018 |Eclipse |1.7 |HTTP/1.1 RFC2616, javax.websocket, SPDY v3 |3.1 |2.3 |Deprecated / *End of Life January 2018* |8 |2009-2014 |Eclipse/Codehaus |1.6 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |3.0 |2.2 |Deprecated / *End of Life November 2014* |7 |2008-2014 |Eclipse/Codehaus |1.5 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |2.5 |2.1 |Deprecated / *End of Life November 2014* |6 |2006-2010 |Codehaus |1.4-1.5 |HTTP/1.1 RFC2616 |2.5 |2.0 |Deprecated / *End of Life November 2010* diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java index b5642f8841a..90aafa519eb 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java @@ -32,6 +32,7 @@ import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.fcgi.FCGI; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; @@ -44,7 +45,7 @@ public class HttpClientTransportOverFCGI extends AbstractConnectorHttpClientTran public HttpClientTransportOverFCGI(String scriptRoot) { - this(Math.max(1, Runtime.getRuntime().availableProcessors() / 2), false, scriptRoot); + this( Math.max( 1, ProcessorUtils.availableProcessors() / 2), false, scriptRoot); } public HttpClientTransportOverFCGI(int selectors, boolean multiplexed, String scriptRoot) diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java index 1ff27d3583d..d72762f2d63 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java @@ -127,7 +127,9 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec private void releaseBuffer(ByteBuffer buffer) { - assert this.buffer == buffer; + @SuppressWarnings("ReferenceEquality") + boolean isCurrentBuffer = (this.buffer == buffer); + assert(isCurrentBuffer); HttpClient client = destination.getHttpClient(); ByteBufferPool bufferPool = client.getByteBufferPool(); bufferPool.release(buffer); diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java index a98a6e45bf9..98977c52b06 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java @@ -306,9 +306,9 @@ public class ResponseContentParser extends StreamContentParser } @Override - public void badMessage(int status, String reason) + public void badMessage(BadMessageException failure) { - fail(new BadMessageException(status, reason)); + fail(failure); } protected void fail(Throwable failure) diff --git a/jetty-fcgi/fcgi-server/src/main/config/modules/fcgi.mod b/jetty-fcgi/fcgi-server/src/main/config/modules/fcgi.mod index 6a4beaf1ab1..9cb340d4387 100644 --- a/jetty-fcgi/fcgi-server/src/main/config/modules/fcgi.mod +++ b/jetty-fcgi/fcgi-server/src/main/config/modules/fcgi.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Adds the FastCGI implementation to the classpath. diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java index 3c2d55b78d9..a9e7d4fc329 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java @@ -25,7 +25,9 @@ import java.util.concurrent.ConcurrentMap; import org.eclipse.jetty.fcgi.FCGI; import org.eclipse.jetty.fcgi.generator.Flusher; import org.eclipse.jetty.fcgi.parser.ServerParser; +import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; @@ -187,9 +189,7 @@ public class ServerFCGIConnection extends AbstractConnection if (LOG.isDebugEnabled()) LOG.debug("Request {} failure on {}: {}", request, channel, failure); if (channel != null) - { - channel.onBadMessage(400, failure.toString()); - } + channel.onBadMessage(new BadMessageException(HttpStatus.BAD_REQUEST_400, null, failure)); } } } diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java index 2a0243c06cd..15b769f8f3d 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java @@ -40,6 +40,7 @@ import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.proxy.AsyncProxyServlet; +import org.eclipse.jetty.util.ProcessorUtils; /** * Specific implementation of {@link org.eclipse.jetty.proxy.AsyncProxyServlet.Transparent} for FastCGI. @@ -111,7 +112,7 @@ public class FastCGIProxyServlet extends AsyncProxyServlet.Transparent String scriptRoot = config.getInitParameter(SCRIPT_ROOT_INIT_PARAM); if (scriptRoot == null) throw new IllegalArgumentException("Mandatory parameter '" + SCRIPT_ROOT_INIT_PARAM + "' not configured"); - int selectors = Math.max(1, Runtime.getRuntime().availableProcessors() / 2); + int selectors = Math.max( 1, ProcessorUtils.availableProcessors() / 2); String value = config.getInitParameter("selectors"); if (value != null) selectors = Integer.parseInt(value); diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/AbstractHttpClientServerTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/AbstractHttpClientServerTest.java index d8d41f538fd..f212c832a37 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/AbstractHttpClientServerTest.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/AbstractHttpClientServerTest.java @@ -34,6 +34,7 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.toolchain.test.TestTracker; import org.eclipse.jetty.util.LeakDetector; +import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.hamcrest.Matchers; import org.junit.After; @@ -59,8 +60,8 @@ public abstract class AbstractHttpClientServerTest ServerFCGIConnectionFactory fcgiConnectionFactory = new ServerFCGIConnectionFactory(new HttpConfiguration()); serverBufferPool = new LeakTrackingByteBufferPool(new MappedByteBufferPool.Tagged()); - connector = new ServerConnector(server, null, null, serverBufferPool, - 1, Math.max(1, Runtime.getRuntime().availableProcessors() / 2), fcgiConnectionFactory); + connector = new ServerConnector( server, null, null, serverBufferPool, + 1, Math.max( 1, ProcessorUtils.availableProcessors() / 2), fcgiConnectionFactory); // connector.setPort(9000); server.addConnector(connector); diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/gcloud-datastore.mod b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/gcloud-datastore.mod index c65ccd33704..9415b77ed9d 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/gcloud-datastore.mod +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/gcloud-datastore.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables GCloud Datastore API and implementation diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/gcloud.mod b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/gcloud.mod index 454bd6e5581..64e1fb2df00 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/gcloud.mod +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/gcloud.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Control GCloud API classpath diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/session-store-gcloud.mod b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/session-store-gcloud.mod index 1d21cff1b68..69054019de9 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/session-store-gcloud.mod +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/session-store-gcloud.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables GCloudDatastore session management. diff --git a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod index daa55012162..2263ae0807b 100644 --- a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod +++ b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables session data store in an embedded Hazelcast Map diff --git a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod index 55baa0e3d68..c6a26fc7123 100644 --- a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod +++ b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables session data store in a remote Hazelcast Map diff --git a/jetty-home/src/main/resources/modules/conscrypt.mod b/jetty-home/src/main/resources/modules/conscrypt.mod index 0dfe600461e..85b885a89c5 100644 --- a/jetty-home/src/main/resources/modules/conscrypt.mod +++ b/jetty-home/src/main/resources/modules/conscrypt.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Installs the Conscrypt JSSE provider diff --git a/jetty-home/src/main/resources/modules/hawtio.mod b/jetty-home/src/main/resources/modules/hawtio.mod index fd0358ec0a6..a64f8327a0c 100644 --- a/jetty-home/src/main/resources/modules/hawtio.mod +++ b/jetty-home/src/main/resources/modules/hawtio.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Deploys the Hawtio console as a webapplication. diff --git a/jetty-home/src/main/resources/modules/jamon.mod b/jetty-home/src/main/resources/modules/jamon.mod index c8207f9af82..db81214f3e0 100644 --- a/jetty-home/src/main/resources/modules/jamon.mod +++ b/jetty-home/src/main/resources/modules/jamon.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Deploys the JAMon webapplication diff --git a/jetty-home/src/main/resources/modules/jminix.mod b/jetty-home/src/main/resources/modules/jminix.mod index 2e250ddeef3..7f2ff89e3a2 100644 --- a/jetty-home/src/main/resources/modules/jminix.mod +++ b/jetty-home/src/main/resources/modules/jminix.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Deploys the Jminix JMX Console within the server diff --git a/jetty-home/src/main/resources/modules/jolokia.mod b/jetty-home/src/main/resources/modules/jolokia.mod index 054efa4092a..d1d61887044 100644 --- a/jetty-home/src/main/resources/modules/jolokia.mod +++ b/jetty-home/src/main/resources/modules/jolokia.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Deploys the Jolokia console as a web application. diff --git a/jetty-home/src/main/resources/modules/jsp.mod b/jetty-home/src/main/resources/modules/jsp.mod index 2bc7ba85225..12bbcd05b3c 100644 --- a/jetty-home/src/main/resources/modules/jsp.mod +++ b/jetty-home/src/main/resources/modules/jsp.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables JSP for all webapplications deployed on the server. diff --git a/jetty-home/src/main/resources/modules/jstl.mod b/jetty-home/src/main/resources/modules/jstl.mod index dedb2c052c1..7311f47315a 100644 --- a/jetty-home/src/main/resources/modules/jstl.mod +++ b/jetty-home/src/main/resources/modules/jstl.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables JSTL for all webapplications deployed on the server diff --git a/jetty-home/src/main/resources/modules/setuid.mod b/jetty-home/src/main/resources/modules/setuid.mod index c1174ccba8d..be4f8476714 100644 --- a/jetty-home/src/main/resources/modules/setuid.mod +++ b/jetty-home/src/main/resources/modules/setuid.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables the unix setUID configuration so that the server may be started as root to open privileged ports/files before diff --git a/jetty-home/src/main/resources/modules/stop.mod b/jetty-home/src/main/resources/modules/stop.mod index 6a86c04f4d7..a7b8c966c4d 100644 --- a/jetty-home/src/main/resources/modules/stop.mod +++ b/jetty-home/src/main/resources/modules/stop.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] This module causes jetty to stop immediately after starting. This is good for testing configuration and/or precompiling quickstart webapps diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/GZIPContentDecoder.java b/jetty-http/src/main/java/org/eclipse/jetty/http/GZIPContentDecoder.java index 7df8d821e14..e3e0401fbee 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/GZIPContentDecoder.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/GZIPContentDecoder.java @@ -417,7 +417,9 @@ public class GZIPContentDecoder implements Destroyable */ public void release(ByteBuffer buffer) { - if (_pool!=null && buffer!=BufferUtil.EMPTY_BUFFER) + @SuppressWarnings("ReferenceEquality") + boolean isTheEmptyBuffer = (buffer==BufferUtil.EMPTY_BUFFER); + if (_pool!=null && !isTheEmptyBuffer) _pool.release(buffer); } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java index 93fe67b3dbf..adffa595b44 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java @@ -276,9 +276,12 @@ public class HttpField public boolean isSameName(HttpField field) { + @SuppressWarnings("ReferenceEquality") + boolean sameObject = (field==this); + if (field==null) return false; - if (field==this) + if (sameObject) return true; if (_header!=null && _header==field.getHeader()) return true; diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index 8ba94d67dd7..bc146bdf4ac 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -36,6 +36,7 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import static org.eclipse.jetty.http.HttpTokens.CARRIAGE_RETURN; +import static org.eclipse.jetty.http.HttpTokens.COLON; import static org.eclipse.jetty.http.HttpTokens.LINE_FEED; import static org.eclipse.jetty.http.HttpTokens.SPACE; import static org.eclipse.jetty.http.HttpTokens.TAB; @@ -1052,7 +1053,7 @@ public class HttpParser throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Header Folding"); // header value without name - continuation? - if (_valueString==null) + if (_valueString==null || _valueString.isEmpty()) { _string.setLength(0); _length=0; @@ -1144,10 +1145,6 @@ public class HttpParser default: { - // now handle the ch - if (bHttpTokens.SPACE && b!=HttpTokens.COLON) + switch(b) { - if (_header!=null) - { - setString(_header.asString()); - _header=null; - _headerString=null; - } - - _string.append((char)b); - _length=_string.length(); - break; - } - - // Fallthrough - - case WS_AFTER_NAME: - if (b==HttpTokens.COLON) - { - if (_headerString==null) - { + case SPACE: + case TAB: + //Ignore trailing whitespaces ? + if (!complianceViolation(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME,null)) + { + _headerString=takeString(); + _header=HttpHeader.CACHE.get(_headerString); + _length=-1; + setState(FieldState.WS_AFTER_NAME); + break; + } + throw new IllegalCharacterException(_state,b,buffer); + + case COLON: _headerString=takeString(); _header=HttpHeader.CACHE.get(_headerString); - } - _length=-1; - - setState(FieldState.VALUE); - break; - } - - if (b==HttpTokens.LINE_FEED) - { - if (_headerString==null) - { - _headerString=takeString(); - _header=HttpHeader.CACHE.get(_headerString); - } - _string.setLength(0); - _valueString=""; - _length=-1; - - if (!complianceViolation(HttpComplianceSection.FIELD_COLON,_headerString)) - { - setState(FieldState.FIELD); + _length=-1; + setState(FieldState.VALUE); break; - } - } + + case LINE_FEED: + _headerString=takeString(); + _header=HttpHeader.CACHE.get(_headerString); + _string.setLength(0); + _valueString=""; + _length=-1; - //Ignore trailing whitespaces - if (b==HttpTokens.SPACE && !complianceViolation(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME,null)) + if (!complianceViolation(HttpComplianceSection.FIELD_COLON,_headerString)) + { + setState(FieldState.FIELD); + break; + } + throw new IllegalCharacterException(_state,b,buffer); + + default: + if (b<0) + throw new IllegalCharacterException(_state,b,buffer); + + _string.append((char)b); + _length=_string.length(); + break; + } + break; + + case WS_AFTER_NAME: + + switch(b) { - setState(FieldState.WS_AFTER_NAME); - break; - } + case SPACE: + case TAB: + break; - throw new IllegalCharacterException(_state,b,buffer); + case COLON: + setState(FieldState.VALUE); + break; + + case LINE_FEED: + if (!complianceViolation(HttpComplianceSection.FIELD_COLON,_headerString)) + { + setState(FieldState.FIELD); + break; + } + throw new IllegalCharacterException(_state,b,buffer); + + default: + throw new IllegalCharacterException(_state,b,buffer); + } + break; case VALUE: - if (b>HttpTokens.SPACE || b<0) + switch(b) { - _string.append((char)(0xff&b)); - _length=_string.length(); - setState(FieldState.IN_VALUE); - break; - } - - if (b==HttpTokens.SPACE || b==HttpTokens.TAB) - break; - - if (b==HttpTokens.LINE_FEED) - { - _string.setLength(0); - _valueString=""; - _length=-1; - - setState(FieldState.FIELD); - break; - } - throw new IllegalCharacterException(_state,b,buffer); - - case IN_VALUE: - if (b>=HttpTokens.SPACE || b<0 || b==HttpTokens.TAB) - { - if (_valueString!=null) - { - setString(_valueString); - _valueString=null; - _field=null; - } - _string.append((char)(0xff&b)); - if (b>HttpTokens.SPACE || b<0) - _length=_string.length(); - break; - } - - if (b==HttpTokens.LINE_FEED) - { - if (_length > 0) - { - _valueString=takeString(); + case LINE_FEED: + _string.setLength(0); + _valueString=""; _length=-1; - } - setState(FieldState.FIELD); + + setState(FieldState.FIELD); + break; + + case SPACE: + case TAB: + break; + + default: + _string.append((char)(0xff&b)); + _length=_string.length(); + setState(FieldState.IN_VALUE); break; } - - throw new IllegalCharacterException(_state,b,buffer); - + break; + + case IN_VALUE: + switch(b) + { + case LINE_FEED: + if (_length > 0) + { + _valueString=takeString(); + _length=-1; + } + setState(FieldState.FIELD); + break; + + case SPACE: + case TAB: + _string.append((char)(0xff&b)); + break; + + default: + _string.append((char)(0xff&b)); + _length=_string.length(); + break; + } + break; + default: throw new IllegalStateException(_state.toString()); @@ -1477,7 +1484,7 @@ public class HttpParser if (DEBUG) LOG.debug("{} EOF in {}",this,_state); setState(State.CLOSED); - _handler.badMessage(HttpStatus.BAD_REQUEST_400,null); + _handler.badMessage(new BadMessageException(HttpStatus.BAD_REQUEST_400)); break; } } @@ -1503,7 +1510,7 @@ public class HttpParser if (_headerComplete) _handler.earlyEOF(); else - _handler.badMessage(x._code, x._reason); + _handler.badMessage(x); } protected boolean parseContent(ByteBuffer buffer) @@ -1782,10 +1789,20 @@ public class HttpParser /* ------------------------------------------------------------ */ /** Called to signal that a bad HTTP message has been received. - * @param status The bad status to send - * @param reason The textual reason for badness + * @param failure the failure with the bad message information */ - public void badMessage(int status, String reason); + public default void badMessage(BadMessageException failure) + { + badMessage(failure.getCode(), failure.getReason()); + } + + /** + * @deprecated use {@link #badMessage(BadMessageException)} instead + */ + @Deprecated + public default void badMessage(int status, String reason) + { + } /* ------------------------------------------------------------ */ /** @return the size in bytes of the per parser header cache diff --git a/jetty-http/src/main/resources/org/eclipse/jetty/http/encoding.properties b/jetty-http/src/main/resources/org/eclipse/jetty/http/encoding.properties index e8b1d7bdc02..3f2d2dd358e 100644 --- a/jetty-http/src/main/resources/org/eclipse/jetty/http/encoding.properties +++ b/jetty-http/src/main/resources/org/eclipse/jetty/http/encoding.properties @@ -1,11 +1,12 @@ # Mapping of mime type to inferred or assumed charset # inferred charsets are used for encoding/decoding and explicitly set in associated metadata # assumed charsets are used for encoding/decoding, but are not set in associated metadata -# In this file, assumed charsets are indicatd with a leading '-' +# In this file, assumed charsets are indicated with a leading '-' text/html=utf-8 text/plain=iso-8859-1 text/xml=utf-8 application/xhtml+xml=utf-8 text/json=-utf-8 +application/json=-utf-8 application/vnd.api+json=-utf-8 \ No newline at end of file diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java index 6f1d21eb8e5..e071a362d7b 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java @@ -18,13 +18,6 @@ package org.eclipse.jetty.http; -import static org.hamcrest.Matchers.either; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; @@ -38,6 +31,12 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; +import static org.hamcrest.Matchers.either; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + @RunWith(Parameterized.class) public class HttpGeneratorServerHTTPTest { @@ -261,9 +260,9 @@ public class HttpGeneratorServerHTTPTest } @Override - public void badMessage(int status, String reason) + public void badMessage(BadMessageException failure) { - throw new IllegalStateException(reason); + throw failure; } @Override diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java index ec97769fde3..5d7b6207e28 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java @@ -18,8 +18,7 @@ package org.eclipse.jetty.http; -import static org.hamcrest.Matchers.contains; - +import static org.eclipse.jetty.http.HttpComplianceSection.NO_FIELD_FOLDING; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -34,6 +33,8 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import static org.hamcrest.Matchers.contains; + public class HttpParserTest { static @@ -261,6 +262,8 @@ public class HttpParserTest "Host: localhost\r\n" + "Name: value\r\n" + " extra\r\n" + + "Name2: \r\n" + + "\tvalue2\r\n" + "\r\n"); HttpParser.RequestHandler handler = new Handler(); @@ -270,10 +273,12 @@ public class HttpParserTest Assert.assertThat(_bad, Matchers.nullValue()); Assert.assertEquals("Host", _hdr[0]); Assert.assertEquals("localhost", _val[0]); + Assert.assertEquals(2, _headers); Assert.assertEquals("Name", _hdr[1]); Assert.assertEquals("value extra", _val[1]); - Assert.assertEquals(1, _headers); - Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.NO_FIELD_FOLDING)); + Assert.assertEquals("Name2", _hdr[2]); + Assert.assertEquals("value2", _val[2]); + Assert.assertThat(_complianceViolation, contains(NO_FIELD_FOLDING,NO_FIELD_FOLDING)); } @Test @@ -399,7 +404,7 @@ public class HttpParserTest ByteBuffer buffer = BufferUtil.toBuffer( "HTTP/1.1 204 No Content\r\n" + "Access-Control-Allow-Headers : Origin\r\n" + - "Other: value\r\n" + + "Other\t : value\r\n" + "\r\n"); HttpParser.ResponseHandler handler = new Handler(); @@ -422,7 +427,7 @@ public class HttpParserTest Assert.assertEquals("Other", _hdr[1]); Assert.assertEquals("value", _val[1]); - Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME)); + Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME,HttpComplianceSection.NO_WS_AFTER_FIELD_NAME)); } @Test @@ -709,7 +714,9 @@ public class HttpParserTest public void testBadHeaderEncoding() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\nH\u00e6der0: value0\r\n\n\n"); + "GET / HTTP/1.0\r\n" + + "H\u00e6der0: value0\r\n" + + "\n\n"); HttpParser.RequestHandler handler = new Handler(); HttpParser parser = new HttpParser(handler); @@ -2025,6 +2032,7 @@ public class HttpParserTest Assert.assertEquals(null, _bad); } @Test + @SuppressWarnings("ReferenceEquality") public void testCachedField() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( @@ -2200,9 +2208,10 @@ public class HttpParserTest } @Override - public void badMessage(int status, String reason) + public void badMessage(BadMessageException failure) { - _bad = reason == null ? ("" + status) : reason; + String reason = failure.getReason(); + _bad = reason == null ? String.valueOf(failure.getCode()) : reason; } @Override diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java index 2d713f04509..60d5a50c06e 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java @@ -408,9 +408,9 @@ public class HttpTester } @Override - public void badMessage(int status, String reason) + public void badMessage(BadMessageException failure) { - throw new RuntimeException(reason); + throw failure; } public ByteBuffer generate() diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java index 1eb23d3da7b..83ff1c487e7 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.client; import java.io.IOException; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; @@ -122,6 +123,8 @@ public class HTTP2Client extends ContainerLifeCycle private int selectors = 1; private long idleTimeout = 30000; private long connectTimeout = 10000; + private boolean connectBlocking; + private SocketAddress bindAddress; private int inputBufferSize = 8192; private List protocols = Arrays.asList("h2", "h2-17", "h2-16", "h2-15", "h2-14"); private int initialSessionRecvWindow = 16 * 1024 * 1024; @@ -266,6 +269,27 @@ public class HTTP2Client extends ContainerLifeCycle selector.setConnectTimeout(connectTimeout); } + @ManagedAttribute("Whether the connect() operation is blocking") + public boolean isConnectBlocking() + { + return connectBlocking; + } + + public void setConnectBlocking(boolean connectBlocking) + { + this.connectBlocking = connectBlocking; + } + + public SocketAddress getBindAddress() + { + return bindAddress; + } + + public void setBindAddress(SocketAddress bindAddress) + { + this.bindAddress = bindAddress; + } + @ManagedAttribute("The size of the buffer used to read from the network") public int getInputBufferSize() { @@ -325,10 +349,23 @@ public class HTTP2Client extends ContainerLifeCycle try { SocketChannel channel = SocketChannel.open(); + SocketAddress bindAddress = getBindAddress(); + if (bindAddress != null) + channel.bind(bindAddress); configure(channel); - channel.configureBlocking(false); + boolean connected = true; + if (isConnectBlocking()) + { + channel.socket().connect(address, (int)getConnectTimeout()); + channel.configureBlocking(false); + } + else + { + channel.configureBlocking(false); + connected = channel.connect(address); + } context = contextFrom(sslContextFactory, address, listener, promise, context); - if (channel.connect(address)) + if (connected) selector.accept(channel, context); else selector.connect(channel, context); diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java index 8d48028f9da..64df651c950 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java @@ -124,15 +124,15 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory { session.frames(null, this, prefaceFrame, settingsFrame); } - // Only start reading from server after we have sent the client preface, - // otherwise we risk to read the server preface (a SETTINGS frame) and - // reply to that before we have the chance to send the client preface. - super.onOpen(); } @Override public void succeeded() { + // Only start reading from server after we have sent the client preface, + // otherwise we risk to read the server preface (a SETTINGS frame) and + // reply to that before we have the chance to send the client preface. + super.onOpen(); promise.succeeded(getSession()); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java index 9199bf665d8..cce85626b15 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java @@ -223,7 +223,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable IStream stream = entry.stream; if (stream != null && !entry.isControl()) { - Object channel = stream.getAttribute(IStream.CHANNEL_ATTRIBUTE); + Object channel = stream.getAttachment(); if (channel instanceof WriteFlusher.Listener) ((WriteFlusher.Listener)channel).onFlushed(update - Frame.HEADER_LENGTH); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 4dd88c5f35e..2ebcb2dc6c1 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -89,6 +89,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio private int initialSessionRecvWindow; private boolean pushEnabled; private long idleTime; + private GoAwayFrame closeFrame; public HTTP2Session(Scheduler scheduler, EndPoint endPoint, Generator generator, Session.Listener listener, FlowControlStrategy flowControl, int initialStreamId) { @@ -430,6 +431,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio { // We received a GO_AWAY, so try to write // what's in the queue and then disconnect. + closeFrame = frame; notifyClose(this, frame, new DisconnectCallback()); return; } @@ -597,8 +599,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio { if (closed.compareAndSet(current, CloseState.LOCALLY_CLOSED)) { - GoAwayFrame frame = newGoAwayFrame(error, reason); - control(null, callback, frame); + closeFrame = newGoAwayFrame(CloseState.LOCALLY_CLOSED, error, reason); + control(null, callback, closeFrame); return true; } break; @@ -614,7 +616,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio } } - private GoAwayFrame newGoAwayFrame(int error, String reason) + private GoAwayFrame newGoAwayFrame(CloseState closeState, int error, String reason) { byte[] payload = null; if (reason != null) @@ -623,7 +625,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio reason = reason.substring(0, Math.min(reason.length(), 32)); payload = reason.getBytes(StandardCharsets.UTF_8); } - return new GoAwayFrame(lastStreamId.get(), error, payload); + return new GoAwayFrame(closeState, lastStreamId.get(), error, payload); } @Override @@ -1125,7 +1127,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio @Override public String toString() { - return String.format("%s@%x{l:%s <-> r:%s,sendWindow=%s,recvWindow=%s,streams=%d,%s}", + return String.format("%s@%x{l:%s <-> r:%s,sendWindow=%s,recvWindow=%s,streams=%d,%s,%s}", getClass().getSimpleName(), hashCode(), getEndPoint().getLocalAddress(), @@ -1133,7 +1135,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio sendWindow, recvWindow, streams.size(), - closed); + closed, + closeFrame); } private class ControlEntry extends HTTP2Flusher.Entry @@ -1453,7 +1456,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio private void complete() { - frames(null, Callback.NOOP, newGoAwayFrame(ErrorCode.NO_ERROR.code, null), new DisconnectFrame()); + frames(null, Callback.NOOP, newGoAwayFrame(CloseState.CLOSED, ErrorCode.NO_ERROR.code, null), new DisconnectFrame()); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index e8c10f3d85b..91e635d6b96 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.nio.channels.WritePendingException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; @@ -47,11 +48,13 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa { private static final Logger LOG = Log.getLogger(HTTP2Stream.class); + private final AtomicReference attachment = new AtomicReference<>(); private final AtomicReference> attributes = new AtomicReference<>(); private final AtomicReference closeState = new AtomicReference<>(CloseState.NOT_CLOSED); private final AtomicReference writing = new AtomicReference<>(); private final AtomicInteger sendWindow = new AtomicInteger(); private final AtomicInteger recvWindow = new AtomicInteger(); + private final long timeStamp = System.nanoTime(); private final ISession session; private final int streamId; private final boolean local; @@ -73,6 +76,18 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa return streamId; } + @Override + public Object getAttachment() + { + return attachment.get(); + } + + @Override + public void setAttachment(Object attachment) + { + this.attachment.set(attachment); + } + @Override public boolean isLocal() { @@ -460,7 +475,15 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa @Override public String toString() { - return String.format("%s@%x#%d{sendWindow=%s,recvWindow=%s,reset=%b,%s}", getClass().getSimpleName(), - hashCode(), getId(), sendWindow, recvWindow, isReset(), closeState); + return String.format("%s@%x#%d{sendWindow=%s,recvWindow=%s,reset=%b,%s,age=%d,attachment=%s}", + getClass().getSimpleName(), + hashCode(), + getId(), + sendWindow, + recvWindow, + isReset(), + closeState, + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - timeStamp), + attachment); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java index 669e8c9807d..3fe92bbaf23 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java @@ -32,12 +32,17 @@ import org.eclipse.jetty.util.Callback; public interface IStream extends Stream, Closeable { /** - *

The constant used as attribute key to store/retrieve the HTTP - * channel associated with this stream

- * - * @see #setAttribute(String, Object) + * @return the object attached to this stream + * @see #setAttachment(Object) */ - public static final String CHANNEL_ATTRIBUTE = IStream.class.getName() + ".channel"; + public Object getAttachment(); + + /** + * Attaches the given object to this stream for later retrieval. + * + * @param attachment the object to attach to this stream + */ + public void setAttachment(Object attachment); /** * @return whether this stream is local or remote diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java index 7fcf3cb81cb..e603771dee9 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java @@ -20,17 +20,25 @@ package org.eclipse.jetty.http2.frames; import java.nio.charset.StandardCharsets; +import org.eclipse.jetty.http2.CloseState; import org.eclipse.jetty.http2.ErrorCode; public class GoAwayFrame extends Frame { + private final CloseState closeState; private final int lastStreamId; private final int error; private final byte[] payload; public GoAwayFrame(int lastStreamId, int error, byte[] payload) + { + this(CloseState.REMOTELY_CLOSED, lastStreamId, error, payload); + } + + public GoAwayFrame(CloseState closeState, int lastStreamId, int error, byte[] payload) { super(FrameType.GO_AWAY); + this.closeState = closeState; this.lastStreamId = lastStreamId; this.error = error; this.payload = payload; @@ -69,10 +77,11 @@ public class GoAwayFrame extends Frame public String toString() { ErrorCode errorCode = ErrorCode.from(error); - return String.format("%s,%d/%s/%s", + return String.format("%s,%d/%s/%s/%s", super.toString(), lastStreamId, errorCode != null ? errorCode.toString() : String.valueOf(error), - tryConvertPayload()); + tryConvertPayload(), + closeState); } } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java index 0afca53f3cc..8af7b0e11e5 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java @@ -131,6 +131,7 @@ public class HpackContextTest assertNull(ctx.get("name")); } @Test + @SuppressWarnings("ReferenceEquality") public void testGetAddStatic() { HpackContext ctx = new HpackContext(4096); diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java index b3372e49f6f..cdc4662fc1a 100644 --- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java @@ -120,4 +120,13 @@ public class HttpChannelOverHTTP2 extends HttpChannel super.exchangeTerminated(exchange, result); release(); } + + @Override + public String toString() + { + return String.format("%s[send=%s,recv=%s]", + super.toString(), + sender, + receiver); + } } diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java index 0bcb1ceb05e..f024d8974ef 100644 --- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java +++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java @@ -124,14 +124,17 @@ public class HttpClientTransportOverHTTP2 extends AbstractHttpClientTransport @Override public void connect(InetSocketAddress address, Map context) { - client.setConnectTimeout(getHttpClient().getConnectTimeout()); + HttpClient httpClient = getHttpClient(); + client.setConnectTimeout(httpClient.getConnectTimeout()); + client.setConnectBlocking(httpClient.isConnectBlocking()); + client.setBindAddress(httpClient.getBindAddress()); SessionListenerPromise listenerPromise = new SessionListenerPromise(context); HttpDestinationOverHTTP2 destination = (HttpDestinationOverHTTP2)context.get(HTTP_DESTINATION_CONTEXT_KEY); SslContextFactory sslContextFactory = null; if (HttpScheme.HTTPS.is(destination.getScheme())) - sslContextFactory = getHttpClient().getSslContextFactory(); + sslContextFactory = httpClient.getSslContextFactory(); client.connect(sslContextFactory, address, listenerPromise, listenerPromise, context); } diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java index 6a3a99e749c..4950c949d3d 100644 --- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java +++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java @@ -29,6 +29,7 @@ import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; @@ -64,7 +65,8 @@ public class HttpSenderOverHTTP2 extends HttpSender @Override public void succeeded(Stream stream) { - getHttpChannel().setStream(stream); + channel.setStream(stream); + ((IStream)stream).setAttachment(channel); stream.setIdleTimeout(request.getIdleTimeout()); if (content.hasContent() && !expects100Continue(request)) diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java index 4504744cf5c..e08ee60b539 100644 --- a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java +++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java @@ -25,6 +25,7 @@ import java.net.ServerSocket; import java.net.Socket; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -534,6 +535,34 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest } } + @Test + public void test204WithContent() throws Exception + { + byte[] bytes = "No Content".getBytes(StandardCharsets.UTF_8); + start(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + int streamId = stream.getId(); + MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.NO_CONTENT_204, new HttpFields()); + HeadersFrame responseFrame = new HeadersFrame(streamId, response, null, false); + Callback.Completable callback = new Callback.Completable(); + stream.headers(responseFrame, callback); + callback.thenRun(() -> stream.data(new DataFrame(streamId, ByteBuffer.wrap(bytes), true), Callback.NOOP)); + return null; + } + }); + + ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) + .timeout(5, TimeUnit.SECONDS) + .send(); + + Assert.assertEquals(HttpStatus.NO_CONTENT_204, response.getStatus()); + // No logic on the client to discard content for no-content status codes. + Assert.assertArrayEquals(bytes, response.getContent()); + } + @Ignore @Test public void testExternalServer() throws Exception diff --git a/jetty-http2/http2-server/src/main/config/modules/http2.mod b/jetty-http2/http2-server/src/main/config/modules/http2.mod index e5def621a6a..2ca6596e578 100644 --- a/jetty-http2/http2-server/src/main/config/modules/http2.mod +++ b/jetty-http2/http2-server/src/main/config/modules/http2.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables HTTP2 protocol support on the TLS(SSL) Connector, using the ALPN extension to select which protocol to use. diff --git a/jetty-http2/http2-server/src/main/config/modules/http2c.mod b/jetty-http2/http2-server/src/main/config/modules/http2c.mod index 228d5a8ca31..b109a8c4ce8 100644 --- a/jetty-http2/http2-server/src/main/config/modules/http2c.mod +++ b/jetty-http2/http2-server/src/main/config/modules/http2c.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables the HTTP2C protocol on the HTTP Connector The connector will accept both HTTP/1 and HTTP/2 connections. diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java index fb18d564a72..f0cbf40091b 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java @@ -25,6 +25,7 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.Queue; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicLong; @@ -172,7 +173,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection { if (LOG.isDebugEnabled()) LOG.debug("Processing {} on {}", frame, stream); - HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE); + HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttachment(); if (channel != null) { Runnable task = channel.onRequestContent(frame, callback); @@ -189,7 +190,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection { if (LOG.isDebugEnabled()) LOG.debug("Processing trailers {} on {}", frame, stream); - HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE); + HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttachment(); if (channel != null) { Runnable task = channel.onRequestTrailers(frame); @@ -200,7 +201,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection public boolean onStreamTimeout(IStream stream, Throwable failure) { - HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE); + HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttachment(); boolean result = channel != null && channel.onStreamTimeout(failure, task -> offerTask(task, true)); if (LOG.isDebugEnabled()) LOG.debug("{} idle timeout on {}: {}", result ? "Processed" : "Ignored", stream, failure); @@ -211,7 +212,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection { if (LOG.isDebugEnabled()) LOG.debug("Processing failure on {}: {}", stream, failure); - HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE); + HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttachment(); if (channel != null) { Runnable task = channel.onFailure(failure, callback); @@ -227,13 +228,13 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection public boolean onSessionTimeout(Throwable failure) { ISession session = getSession(); - boolean result = true; - for (Stream stream : session.getStreams()) - { - HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE); - if (channel != null) - result &= channel.isRequestIdle(); - } + // Compute whether all requests are idle. + boolean result = session.getStreams().stream() + .map(stream -> (IStream)stream) + .map(stream -> (HttpChannelOverHTTP2)stream.getAttachment()) + .filter(Objects::nonNull) + .map(HttpChannelOverHTTP2::isRequestIdle) + .reduce(true, Boolean::logicalAnd); if (LOG.isDebugEnabled()) LOG.debug("{} idle timeout on {}: {}", result ? "Processed" : "Ignored", session, failure); return result; @@ -284,7 +285,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection if (LOG.isDebugEnabled()) LOG.debug("Creating channel {} for {}", channel, this); } - stream.setAttribute(IStream.CHANNEL_ATTRIBUTE, channel); + stream.setAttachment(channel); return channel; } @@ -379,7 +380,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection @Override public void recycle() { - getStream().removeAttribute(IStream.CHANNEL_ATTRIBUTE); + getStream().setAttachment(null); super.recycle(); offerHttpChannel(this); } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 007976d24b6..bfbe7c56195 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -145,12 +145,12 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable, Writ } catch (BadMessageException x) { - onBadMessage(x.getCode(), x.getReason()); + onBadMessage(x); return null; } catch (Throwable x) { - onBadMessage(HttpStatus.INTERNAL_SERVER_ERROR_500, null); + onBadMessage(new BadMessageException(HttpStatus.INTERNAL_SERVER_ERROR_500, null, x)); return null; } } @@ -177,12 +177,12 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable, Writ } catch (BadMessageException x) { - onBadMessage(x.getCode(), x.getReason()); + onBadMessage(x); return null; } catch (Throwable x) { - onBadMessage(HttpStatus.INTERNAL_SERVER_ERROR_500, null); + onBadMessage(new BadMessageException(HttpStatus.INTERNAL_SERVER_ERROR_500, null, x)); return null; } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index b11817837fe..d862891c8f8 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -248,7 +248,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport // Consume the existing queued data frames to // avoid stalling the session flow control. - HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE); + HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttachment(); if (channel != null) channel.consumeInput(); } diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded-910.mod b/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded-910.mod index 96b6acb23e1..e7c8f425f8a 100644 --- a/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded-910.mod +++ b/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded-910.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables session data store in a local Infinispan cache diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded.mod b/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded.mod index 1110aaadbd3..21dc1e65c9b 100644 --- a/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded.mod +++ b/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables session data store in a local Infinispan cache diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote-910.mod b/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote-910.mod index 36493531d38..93903bd41a3 100644 --- a/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote-910.mod +++ b/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote-910.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables session data store in a remote Infinispan cache diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote.mod b/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote.mod index 0ad03b4f512..844b47323cb 100644 --- a/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote.mod +++ b/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables session data store in a remote Infinispan cache diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java index 5695e988e45..105bbd74584 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java @@ -62,6 +62,8 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint protected final void shutdownInput() { + if (LOG.isDebugEnabled()) + LOG.debug("shutdownInput {}",this); while(true) { State s = _state.get(); @@ -114,6 +116,8 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint @Override public final void shutdownOutput() { + if (LOG.isDebugEnabled()) + LOG.debug("shutdownOutput {}",this); while(true) { State s = _state.get(); @@ -166,11 +170,15 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint @Override public final void close() { + if (LOG.isDebugEnabled()) + LOG.debug("close {}",this); close(null); } protected final void close(Throwable failure) { + if (LOG.isDebugEnabled()) + LOG.debug("close({}) {}",failure,this); while(true) { State s = _state.get(); diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java index 409da35e8e4..0b25f5600e6 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java @@ -202,7 +202,7 @@ public class ByteArrayEndPoint extends AbstractEndPoint throw new ClosedChannelException(); ByteBuffer in = _inQ.peek(); - if (BufferUtil.hasContent(in) || in==EOF) + if (BufferUtil.hasContent(in) || isEOF(in)) execute(_runFillable); } } @@ -224,7 +224,7 @@ public class ByteArrayEndPoint extends AbstractEndPoint boolean fillable=false; try(Locker.Lock lock = _locker.lock()) { - if (_inQ.peek()==EOF) + if (isEOF(_inQ.peek())) throw new RuntimeIOException(new EOFException()); boolean was_empty=_inQ.isEmpty(); if (in==null) @@ -248,7 +248,7 @@ public class ByteArrayEndPoint extends AbstractEndPoint boolean fillable=false; try(Locker.Lock lock = _locker.lock()) { - if (_inQ.peek()==EOF) + if (isEOF(_inQ.peek())) throw new RuntimeIOException(new EOFException()); boolean was_empty=_inQ.isEmpty(); if (in==null) @@ -415,7 +415,7 @@ public class ByteArrayEndPoint extends AbstractEndPoint break; ByteBuffer in= _inQ.peek(); - if (in==EOF) + if (isEOF(in)) { filled=-1; break; @@ -550,4 +550,16 @@ public class ByteArrayEndPoint extends AbstractEndPoint return String.format("%s[q=%d,q[0]=%s,o=%s]",super.toString(),q,b,o); } + /* ------------------------------------------------------------ */ + /** + * Compares a ByteBuffer Object to EOF by Reference + * @param buffer the input ByteBuffer to be compared to EOF + * @return Whether the reference buffer is equal to that of EOF + */ + private static boolean isEOF(ByteBuffer buffer) + { + @SuppressWarnings("ReferenceEquality") + boolean is_EOF = (buffer==EOF); + return is_EOF; + } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ConnectionStatistics.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ConnectionStatistics.java index 6ea289b805e..871d57c6353 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ConnectionStatistics.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ConnectionStatistics.java @@ -94,7 +94,7 @@ public class ConnectionStatistics extends AbstractLifeCycle implements Connectio _connections.decrement(); long elapsed = System.currentTimeMillis() - connection.getCreatedTimeStamp(); - _connectionsDuration.set(elapsed); + _connectionsDuration.record(elapsed); long bytesIn = connection.getBytesIn(); if (bytesIn > 0) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java index 90adb5c7873..eb18828a44e 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java @@ -185,24 +185,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable if (connect.timeout.cancel()) { key.interestOps(0); - execute(new Runnable() - { - @Override - public void run() - { - try - { - createEndPoint(channel,key); - } - catch(Throwable failure) - { - closeNoExceptions(channel); - LOG.warn(String.valueOf(failure)); - LOG.debug(failure); - connect.failed(failure); - } - } - }); + execute(new CreateEndPoint(connect,key)); } else { @@ -262,16 +245,15 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable @Override public void dump(Appendable out, String indent) throws IOException { + List keys; + List updates; Selector selector = _selector; - List keys = null; - List updates = null; if (selector != null && selector.isOpen()) { DumpKeys dump = new DumpKeys(); - String updatesAt; + String updatesAt = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now()); synchronized(ManagedSelector.this) { - updatesAt = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now()); updates = new ArrayList<>(_updates); _updates.addFirst(dump); _selecting = false; @@ -338,7 +320,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable return task; processUpdates(); - + updateKeys(); if (!select()) @@ -388,7 +370,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable LOG.debug("updates {}",updates); if (selector != null) - selector.wakeup(); + selector.wakeup(); } private boolean select() @@ -401,6 +383,8 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable if (LOG.isDebugEnabled()) LOG.debug("Selector {} waiting on select", selector); int selected = selector.select(); + if (selected == 0) + selected = selector.selectNow(); if (LOG.isDebugEnabled()) LOG.debug("Selector {} woken up from select, {}/{} selected", selector, selected, selector.keys().size()); @@ -413,7 +397,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable } _keys = selector.selectedKeys(); - _cursor = _keys.iterator(); + _cursor = _keys.isEmpty() ? Collections.emptyIterator() : _keys.iterator(); if (LOG.isDebugEnabled()) LOG.debug("Selector {} processing {} keys, {} updates", selector, _keys.size(), updates); @@ -730,6 +714,12 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable ManagedSelector.this._selectorManager.connectionFailed(channel, failure, attachment); } } + + @Override + public String toString() + { + return String.format("Connect@%x{%s,%s}",hashCode(),channel,attachment); + } } private class CloseConnections implements SelectorUpdate @@ -816,7 +806,40 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable } } + private final class CreateEndPoint implements Runnable + { + private final Connect _connect; + private final SelectionKey _key; + private CreateEndPoint(Connect connect, SelectionKey key) + { + _connect = connect; + _key = key; + } + + @Override + public void run() + { + try + { + createEndPoint(_connect.channel,_key); + } + catch(Throwable failure) + { + closeNoExceptions(_connect.channel); + LOG.warn(String.valueOf(failure)); + LOG.debug(failure); + _connect.failed(failure); + } + } + + @Override + public String toString() + { + return String.format("CreateEndPoint@%x{%s,%s}",hashCode(),_connect,_key); + } + } + private class DestroyEndPoint implements Runnable, Closeable { private final EndPoint endPoint; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java index 4717da83364..a311c91c80f 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java @@ -32,6 +32,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.IntUnaryOperator; +import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.component.ContainerLifeCycle; @@ -68,10 +69,10 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump if (executor instanceof ThreadPool.SizedThreadPool) { int threads = ((ThreadPool.SizedThreadPool)executor).getMaxThreads(); - int cpus = Runtime.getRuntime().availableProcessors(); + int cpus = ProcessorUtils.availableProcessors(); return Math.max(1,Math.min(cpus/2,threads/16)); } - return Math.max(1,Runtime.getRuntime().availableProcessors()/2); + return Math.max(1,ProcessorUtils.availableProcessors()/2); } protected SelectorManager(Executor executor, Scheduler scheduler) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java index 7a8e11034c7..07441e3e4bb 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java @@ -81,7 +81,8 @@ import org.eclipse.jetty.util.thread.Invocable; public class SslConnection extends AbstractConnection { private static final Logger LOG = Log.getLogger(SslConnection.class); - + private static final ThreadLocal __tryWriteAgain = new ThreadLocal<>(); + private final List handshakeListeners = new ArrayList<>(); private final ByteBufferPool _bufferPool; private final SSLEngine _sslEngine; @@ -95,7 +96,7 @@ public class SslConnection extends AbstractConnection private int _renegotiationLimit = -1; private boolean _closedOutbound; private boolean _allowMissingCloseMessage = true; - + private abstract class RunnableTask implements Runnable, Invocable { private final String _operation; @@ -506,11 +507,12 @@ public class SslConnection extends AbstractConnection } else { + // TODO This should not be required and we should be able to do all retries within flush // We can get here because the WriteFlusher might not see progress // when it has just flushed the encrypted data, but not consumed anymore // of the application buffers. This is mostly avoided by another iteration - // within DecryptedEndPoint flush(), but I cannot convince myself that - // this is never ever the case. + // within DecryptedEndPoint flush(), but this still occurs sometime on some + // tests on some systems??? More investigation is needed! try_again = true; } } @@ -526,14 +528,35 @@ public class SslConnection extends AbstractConnection { // don't bother writing, just notify of close getWriteFlusher().onClose(); + return; + } + + // TODO this ugly recursion protection is only needed until we remove the try again + // logic from this method and make flush do the try again. + Boolean tryWriteAgain = __tryWriteAgain.get(); + if (tryWriteAgain==null) + { + try + { + // Keep running complete write until + __tryWriteAgain.set(Boolean.FALSE); + do + { + _runCompleteWrite.run(); + } + while (Boolean.TRUE.equals(__tryWriteAgain.get())); + } + finally + { + __tryWriteAgain.remove(); + } } - // Else, else { - // try to flush what is pending - // execute to avoid recursion - getExecutor().execute(_runCompleteWrite); + // Don't recurse but get top caller to iterate + __tryWriteAgain.set(Boolean.TRUE); } + } } @@ -627,8 +650,12 @@ public class SslConnection extends AbstractConnection // We also need an app buffer, but can use the passed buffer if it is big enough ByteBuffer app_in; + boolean used_passed_buffer = false; if (BufferUtil.space(buffer) > _sslEngine.getSession().getApplicationBufferSize()) + { app_in = buffer; + used_passed_buffer = true; + } else if (_decryptedInput == null) app_in = _decryptedInput = _bufferPool.acquire(_sslEngine.getSession().getApplicationBufferSize(), _decryptedDirectBuffers); else @@ -730,7 +757,7 @@ public class SslConnection extends AbstractConnection // another call to fill() or flush(). if (unwrapResult.bytesProduced() > 0) { - if (app_in == buffer) + if (used_passed_buffer) return unwrapResult.bytesProduced(); return BufferUtil.append(buffer,_decryptedInput); } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayByteBufferPoolTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayByteBufferPoolTest.java index 7b2dd9f2cfd..fef7a562023 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayByteBufferPoolTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayByteBufferPoolTest.java @@ -29,6 +29,7 @@ import java.util.Arrays; import org.eclipse.jetty.io.ByteBufferPool.Bucket; import org.junit.Test; +@SuppressWarnings("ReferenceEquality") public class ArrayByteBufferPoolTest { @Test @@ -113,6 +114,7 @@ public class ArrayByteBufferPoolTest } @Test + @SuppressWarnings("ReferenceEquality") public void testAcquireReleaseAcquire() throws Exception { ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10,100,1000); diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java index 98acf13a35b..e50cf959623 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java @@ -293,9 +293,9 @@ public class ByteArrayEndPointTest assertEquals("test", BufferUtil.toString(buffer)); // Wait for a read timeout. + long start = System.nanoTime(); fcb = new FutureCallback(); endp.fillInterested(fcb); - long start = System.nanoTime(); try { fcb.get(); @@ -308,40 +308,5 @@ public class ByteArrayEndPointTest assertThat(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start), greaterThan(halfIdleTimeout)); assertThat("Endpoint open", endp.isOpen(), is(true)); - // We need to delay the write timeout test below from the read timeout test above. - // The reason is that the scheduler thread that fails the endPoint WriteFlusher - // because of the read timeout above runs concurrently with the write below, and - // if it runs just after the write below, the test fails because the write callback - // below fails immediately rather than after the idle timeout. - Thread.sleep(halfIdleTimeout); - - // Write more than the output capacity, then wait for idle timeout. - fcb = new FutureCallback(); - start = System.nanoTime(); - endp.write(fcb, BufferUtil.toBuffer("This is too long")); - try - { - fcb.get(); - fail(); - } - catch (ExecutionException t) - { - assertThat(t.getCause(), instanceOf(TimeoutException.class)); - } - assertThat(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start), greaterThan(halfIdleTimeout)); - // Still open because it has not been oshut or closed explicitly. - assertThat("Endpoint open", endp.isOpen(), is(true)); - - // Make sure the endPoint is closed when the callback fails. - endp.fillInterested(new Closer(endp)); - Thread.sleep(halfIdleTimeout); - // Still open because it has not been oshut or closed explicitly. - assertThat("Endpoint open", endp.isOpen(), is(true)); - - // Shutdown output. - endp.shutdownOutput(); - - Thread.sleep(idleTimeout); - assertThat("Endpoint closed", endp.isOpen(), is(false)); } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java index c43b13aa82c..21e96e4d3aa 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java @@ -514,40 +514,28 @@ public class IOTest assertThat(key,notNullValue()); assertThat(selector.selectNow(), is(0)); - client.write(BufferUtil.toBuffer("X")); - assertThat(selector.select(), is(1)); - assertThat(key.readyOps(), is(SelectionKey.OP_READ)); - assertThat(selector.selectedKeys(), Matchers.contains(key)); - - assertThat(selector.select(), is(0)); - assertThat(key.readyOps(), is(SelectionKey.OP_READ)); - assertThat(selector.selectedKeys(), Matchers.contains(key)); - - client.write(BufferUtil.toBuffer("X")); - selector.selectedKeys().clear(); - assertThat(selector.select(), is(1)); - assertThat(key.readyOps(), is(SelectionKey.OP_READ)); - assertThat(selector.selectedKeys(), Matchers.contains(key)); - - ByteBuffer buf = BufferUtil.allocate(1024); - int p = BufferUtil.flipToFill(buf); - assertThat(server.read(buf),is(2)); - BufferUtil.flipToFlush(buf,p); - + // Test wakeup before select selector.wakeup(); - selector.selectedKeys().clear(); assertThat(selector.select(), is(0)); - assertThat(selector.selectedKeys().size(),is(0)); - client.write(BufferUtil.toBuffer("X")); - selector.wakeup(); - selector.selectedKeys().clear(); - assertThat(selector.select(), is(1)); - assertThat(selector.selectedKeys().size(),is(1)); - - p = BufferUtil.flipToFill(buf); - assertThat(server.read(buf),is(1)); - BufferUtil.flipToFlush(buf,p); - + // Test wakeup after select + new Thread() + { + @Override + public void run() + { + try + { + Thread.sleep(100); + selector.wakeup(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + + }.start(); + assertThat(selector.select(), is(0)); } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/IdleTimeoutTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/IdleTimeoutTest.java index 0780c0cad0d..c35ec08d144 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/IdleTimeoutTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/IdleTimeoutTest.java @@ -120,17 +120,19 @@ public class IdleTimeoutTest @Test public void testShorten() throws Exception - { - for (int i=0;i<20;i++) + { + _timeout.setIdleTimeout(2000); + + for (int i=0;i<30;i++) { - Thread.sleep(200); + Thread.sleep(100); _timeout.notIdle(); } Assert.assertNull(_expired); _timeout.setIdleTimeout(100); long start = System.nanoTime(); - while (_expired==null && TimeUnit.NANOSECONDS.toSeconds(System.nanoTime()-start)<4) + while (_expired==null && TimeUnit.NANOSECONDS.toSeconds(System.nanoTime()-start)<5) Thread.sleep(200); Assert.assertNotNull(_expired); diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointTest.java deleted file mode 100644 index dcaa5f7982c..00000000000 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointTest.java +++ /dev/null @@ -1,833 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.io; - -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.hamcrest.Matchers.lessThan; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; -import java.net.SocketTimeoutException; -import java.nio.ByteBuffer; -import java.nio.channels.SelectableChannel; -import java.nio.channels.SelectionKey; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; -import java.nio.charset.StandardCharsets; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.FutureCallback; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.eclipse.jetty.util.thread.Scheduler; -import org.eclipse.jetty.util.thread.TimerScheduler; -import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -public class SelectChannelEndPointTest -{ - private static final Logger LOG = Log.getLogger(SelectChannelEndPointTest.class); - protected CountDownLatch _lastEndPointLatch; - protected volatile EndPoint _lastEndPoint; - protected ServerSocketChannel _connector; - protected QueuedThreadPool _threadPool = new QueuedThreadPool(); - protected Scheduler _scheduler = new TimerScheduler(); - protected SelectorManager _manager = new SelectorManager(_threadPool, _scheduler) - { - @Override - public Connection newConnection(SelectableChannel channel, EndPoint endpoint, Object attachment) - { - return SelectChannelEndPointTest.this.newConnection(channel, endpoint); - } - - @Override - protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey key) throws IOException - { - SocketChannelEndPoint endp = new SocketChannelEndPoint(channel, selector, key, getScheduler()); - endp.setIdleTimeout(60000); - _lastEndPoint = endp; - _lastEndPointLatch.countDown(); - return endp; - } - - }; - - // Must be volatile or the test may fail spuriously - protected volatile int _blockAt = 0; - private volatile int _writeCount = 1; - - @Before - public void startManager() throws Exception - { - System.gc(); - _writeCount = 1; - _lastEndPoint = null; - _lastEndPointLatch = new CountDownLatch(1); - _connector = ServerSocketChannel.open(); - _connector.socket().bind(null); - _scheduler.start(); - _threadPool.start(); - _manager.start(); - } - - @After - public void stopManager() throws Exception - { - _scheduler.stop(); - _manager.stop(); - _threadPool.stop(); - _connector.close(); - } - - protected Socket newClient() throws IOException - { - return new Socket(_connector.socket().getInetAddress(), _connector.socket().getLocalPort()); - } - - protected Connection newConnection(SelectableChannel channel, EndPoint endpoint) - { - return new TestConnection(endpoint); - } - - public class TestConnection extends AbstractConnection - { - volatile FutureCallback _blockingRead; - ByteBuffer _in = BufferUtil.allocate(32 * 1024); - ByteBuffer _out = BufferUtil.allocate(32 * 1024); - long _last = -1; - final CountDownLatch _latch; - - public TestConnection(EndPoint endp) - { - super(endp, _threadPool); - _latch=null; - } - - public TestConnection(EndPoint endp,CountDownLatch latch) - { - super(endp, _threadPool); - _latch=latch; - } - - @Override - public void onOpen() - { - super.onOpen(); - fillInterested(); - } - - @Override - public void onFillInterestedFailed(Throwable cause) - { - Callback blocking = _blockingRead; - if (blocking!=null) - { - _blockingRead=null; - blocking.failed(cause); - return; - } - super.onFillInterestedFailed(cause); - } - - @Override - public void onFillable() - { - if (_latch!=null) - { - try - { - _latch.await(); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - } - - Callback blocking = _blockingRead; - if (blocking!=null) - { - _blockingRead=null; - blocking.succeeded(); - return; - } - - EndPoint _endp = getEndPoint(); - try - { - _last = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - boolean progress = true; - while (progress) - { - progress = false; - - // Fill the input buffer with everything available - BufferUtil.compact(_in); - if (BufferUtil.isFull(_in)) - throw new IllegalStateException("FULL " + BufferUtil.toDetailString(_in)); - int filled = _endp.fill(_in); - if (filled > 0) - progress = true; - - // If the tests wants to block, then block - while (_blockAt > 0 && _endp.isOpen() && _in.remaining() < _blockAt) - { - FutureCallback future = _blockingRead = new FutureCallback(); - fillInterested(); - future.get(); - filled = _endp.fill(_in); - progress |= filled > 0; - } - - // Copy to the out buffer - if (BufferUtil.hasContent(_in) && BufferUtil.append(_out, _in) > 0) - progress = true; - - // Blocking writes - if (BufferUtil.hasContent(_out)) - { - ByteBuffer out = _out.duplicate(); - BufferUtil.clear(_out); - for (int i = 0; i < _writeCount; i++) - { - FutureCallback blockingWrite = new FutureCallback(); - _endp.write(blockingWrite, out.asReadOnlyBuffer()); - blockingWrite.get(); - } - progress = true; - } - - // are we done? - if (_endp.isInputShutdown()) - _endp.shutdownOutput(); - } - - if (_endp.isOpen()) - fillInterested(); - } - catch (ExecutionException e) - { - // Timeout does not close, so echo exception then shutdown - try - { - FutureCallback blockingWrite = new FutureCallback(); - _endp.write(blockingWrite, BufferUtil.toBuffer("EE: " + BufferUtil.toString(_in))); - blockingWrite.get(); - _endp.shutdownOutput(); - } - catch (Exception e2) - { - // e2.printStackTrace(); - } - } - catch (InterruptedException | EofException e) - { - Log.getRootLogger().ignore(e); - } - catch (Exception e) - { - Log.getRootLogger().warn(e); - } - finally - { - } - } - } - - @Test - public void testEcho() throws Exception - { - Socket client = newClient(); - - client.setSoTimeout(60000); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - - _manager.accept(server); - - // Write client to server - client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); - - // Verify echo server to client - for (char c : "HelloWorld".toCharArray()) - { - int b = client.getInputStream().read(); - assertTrue(b > 0); - assertEquals(c, (char)b); - } - - // wait for read timeout - client.setSoTimeout(500); - long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - try - { - client.getInputStream().read(); - Assert.fail(); - } - catch (SocketTimeoutException e) - { - long duration = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start; - Assert.assertThat("timeout duration", duration, greaterThanOrEqualTo(400L)); - } - - // write then shutdown - client.getOutputStream().write("Goodbye Cruel TLS".getBytes(StandardCharsets.UTF_8)); - - // Verify echo server to client - for (char c : "Goodbye Cruel TLS".toCharArray()) - { - int b = client.getInputStream().read(); - Assert.assertThat("expect valid char integer", b, greaterThan(0)); - assertEquals("expect characters to be same", c, (char)b); - } - client.close(); - - for (int i = 0; i < 10; ++i) - { - if (server.isOpen()) - Thread.sleep(10); - else - break; - } - assertFalse(server.isOpen()); - } - - @Test - public void testShutdown() throws Exception - { - Socket client = newClient(); - - client.setSoTimeout(500); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - - _manager.accept(server); - - // Write client to server - client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); - - // Verify echo server to client - for (char c : "HelloWorld".toCharArray()) - { - int b = client.getInputStream().read(); - assertTrue(b > 0); - assertEquals(c, (char)b); - } - - // wait for read timeout - long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - try - { - client.getInputStream().read(); - Assert.fail(); - } - catch (SocketTimeoutException e) - { - assertTrue(TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start >= 400); - } - - // write then shutdown - client.getOutputStream().write("Goodbye Cruel TLS".getBytes(StandardCharsets.UTF_8)); - client.shutdownOutput(); - - // Verify echo server to client - for (char c : "Goodbye Cruel TLS".toCharArray()) - { - int b = client.getInputStream().read(); - assertTrue(b > 0); - assertEquals(c, (char)b); - } - - // Read close - assertEquals(-1, client.getInputStream().read()); - } - - @Test - public void testReadBlocked() throws Exception - { - Socket client = newClient(); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - - _manager.accept(server); - - OutputStream clientOutputStream = client.getOutputStream(); - InputStream clientInputStream = client.getInputStream(); - - int specifiedTimeout = 1000; - client.setSoTimeout(specifiedTimeout); - - // Write 8 and cause block waiting for 10 - _blockAt = 10; - clientOutputStream.write("12345678".getBytes(StandardCharsets.UTF_8)); - clientOutputStream.flush(); - - Assert.assertTrue(_lastEndPointLatch.await(1, TimeUnit.SECONDS)); - _lastEndPoint.setIdleTimeout(10 * specifiedTimeout); - Thread.sleep((11 * specifiedTimeout) / 10); - - long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - try - { - int b = clientInputStream.read(); - Assert.fail("Should have timed out waiting for a response, but read " + b); - } - catch (SocketTimeoutException e) - { - int elapsed = Long.valueOf(TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start).intValue(); - Assert.assertThat("Expected timeout", elapsed, greaterThanOrEqualTo(3 * specifiedTimeout / 4)); - } - - // write remaining characters - clientOutputStream.write("90ABCDEF".getBytes(StandardCharsets.UTF_8)); - clientOutputStream.flush(); - - // Verify echo server to client - for (char c : "1234567890ABCDEF".toCharArray()) - { - int b = clientInputStream.read(); - assertTrue(b > 0); - assertEquals(c, (char)b); - } - } - - @Test - public void testIdle() throws Exception - { - int idleTimeout = 2000; - - Socket client = newClient(); - - client.setSoTimeout(idleTimeout*10); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - - _manager.accept(server); - - // Write client to server - long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); - - // Verify echo server to client - for (char c : "HelloWorld".toCharArray()) - { - int b = client.getInputStream().read(); - assertTrue(b > 0); - assertEquals(c, (char)b); - } - - Assert.assertTrue(_lastEndPointLatch.await(1, TimeUnit.SECONDS)); - _lastEndPoint.setIdleTimeout(idleTimeout); - - // read until idle shutdown received - int b = client.getInputStream().read(); - assertEquals(-1, b); - long idle = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start; - assertThat(idle, greaterThan(idleTimeout / 2L)); - assertThat(idle, lessThan(idleTimeout * 2L)); - - // But endpoint may still be open for a little bit. - for (int i = 0; i < 20; ++i) - { - if (_lastEndPoint.isOpen()) - Thread.sleep(2 * idleTimeout / 10); - else - break; - } - assertFalse(_lastEndPoint.isOpen()); - } - - @Test - public void testBlockedReadIdle() throws Exception - { - Socket client = newClient(); - InputStream clientInputStream = client.getInputStream(); - OutputStream clientOutputStream = client.getOutputStream(); - - client.setSoTimeout(5000); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - - _manager.accept(server); - - // Write client to server - clientOutputStream.write("HelloWorld".getBytes(StandardCharsets.UTF_8)); - - // Verify echo server to client - for (char c : "HelloWorld".toCharArray()) - { - int b = clientInputStream.read(); - assertTrue(b > 0); - assertEquals(c, (char)b); - } - - Assert.assertTrue(_lastEndPointLatch.await(1, TimeUnit.SECONDS)); - int idleTimeout = 500; - _lastEndPoint.setIdleTimeout(idleTimeout); - - // Write 8 and cause block waiting for 10 - _blockAt = 10; - clientOutputStream.write("12345678".getBytes(StandardCharsets.UTF_8)); - clientOutputStream.flush(); - - // read until idle shutdown received - long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - int b = clientInputStream.read(); - assertEquals('E', b); - long idle = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start; - assertTrue(idle > idleTimeout / 2); - assertTrue(idle < idleTimeout * 2); - - for (char c : "E: 12345678".toCharArray()) - { - b = clientInputStream.read(); - assertTrue(b > 0); - assertEquals(c, (char)b); - } - b = clientInputStream.read(); - assertEquals(-1,b); - - // But endpoint is still open. - if(_lastEndPoint.isOpen()) - // Wait for another idle callback - Thread.sleep(idleTimeout * 2); - - // endpoint is closed. - assertFalse(_lastEndPoint.isOpen()); - } - - @Test - public void testStress() throws Exception - { - Socket client = newClient(); - client.setSoTimeout(30000); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - - _manager.accept(server); - final int writes = 200000; - - final byte[] bytes = "HelloWorld-".getBytes(StandardCharsets.UTF_8); - byte[] count = "0\n".getBytes(StandardCharsets.UTF_8); - BufferedOutputStream out = new BufferedOutputStream(client.getOutputStream()); - final CountDownLatch latch = new CountDownLatch(writes); - final InputStream in = new BufferedInputStream(client.getInputStream()); - final long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - out.write(bytes); - out.write(count); - out.flush(); - - Assert.assertTrue(_lastEndPointLatch.await(1, TimeUnit.SECONDS)); - _lastEndPoint.setIdleTimeout(5000); - - new Thread() - { - @Override - public void run() - { - Thread.currentThread().setPriority(MAX_PRIORITY); - long last = -1; - int count = -1; - try - { - while (latch.getCount() > 0) - { - // Verify echo server to client - for (byte b0 : bytes) - { - int b = in.read(); - Assert.assertThat(b, greaterThan(0)); - assertEquals(0xff & b0, b); - } - - count = 0; - int b = in.read(); - while (b > 0 && b != '\n') - { - count = count * 10 + (b - '0'); - b = in.read(); - } - last = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - - //if (latch.getCount()%1000==0) - // System.out.println(writes-latch.getCount()); - - latch.countDown(); - } - } - catch (Throwable e) - { - - long now = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - System.err.println("count=" + count); - System.err.println("latch=" + latch.getCount()); - System.err.println("time=" + (now - start)); - System.err.println("last=" + (now - last)); - System.err.println("endp=" + _lastEndPoint); - System.err.println("conn=" + _lastEndPoint.getConnection()); - - e.printStackTrace(); - } - } - }.start(); - - // Write client to server - for (int i = 1; i < writes; i++) - { - out.write(bytes); - out.write(Integer.toString(i).getBytes(StandardCharsets.ISO_8859_1)); - out.write('\n'); - if (i % 1000 == 0) - { - //System.err.println(i+"/"+writes); - out.flush(); - } - Thread.yield(); - } - out.flush(); - - long last = latch.getCount(); - while (!latch.await(5, TimeUnit.SECONDS)) - { - //System.err.println(latch.getCount()); - if (latch.getCount() == last) - Assert.fail(); - last = latch.getCount(); - } - - assertEquals(0, latch.getCount()); - } - - @Test - public void testWriteBlocked() throws Exception - { - Socket client = newClient(); - - client.setSoTimeout(10000); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - - _manager.accept(server); - - // Write client to server - _writeCount = 10000; - String data = "Now is the time for all good men to come to the aid of the party"; - client.getOutputStream().write(data.getBytes(StandardCharsets.UTF_8)); - BufferedInputStream in = new BufferedInputStream(client.getInputStream()); - - int byteNum = 0; - try - { - for (int i = 0; i < _writeCount; i++) - { - if (i % 1000 == 0) - TimeUnit.MILLISECONDS.sleep(200); - - // Verify echo server to client - for (int j = 0; j < data.length(); j++) - { - char c = data.charAt(j); - int b = in.read(); - byteNum++; - assertTrue(b > 0); - assertEquals("test-" + i + "/" + j,c,(char)b); - } - - if (i == 0) - _lastEndPoint.setIdleTimeout(60000); - } - } - catch (SocketTimeoutException e) - { - System.err.println("SelectorManager.dump() = " + _manager.dump()); - LOG.warn("Server: " + server); - LOG.warn("Error reading byte #" + byteNum,e); - throw e; - } - - client.close(); - - for (int i = 0; i < 10; ++i) - { - if (server.isOpen()) - Thread.sleep(10); - else - break; - } - assertFalse(server.isOpen()); - } - - - // TODO make this test reliable - @Test - @Ignore - public void testRejectedExecution() throws Exception - { - _manager.stop(); - _threadPool.stop(); - - final CountDownLatch latch = new CountDownLatch(1); - - BlockingQueue q = new ArrayBlockingQueue<>(4); - _threadPool = new QueuedThreadPool(4,4,60000,q); - _manager = new SelectorManager(_threadPool, _scheduler, 1) - { - - @Override - protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey selectionKey) throws IOException - { - SocketChannelEndPoint endp = new SocketChannelEndPoint(channel,selector,selectionKey,getScheduler()); - _lastEndPoint = endp; - _lastEndPointLatch.countDown(); - return endp; - } - - @Override - public Connection newConnection(SelectableChannel channel, EndPoint endpoint, Object attachment) throws IOException - { - return new TestConnection(endpoint,latch); - } - }; - - _threadPool.start(); - _manager.start(); - - AtomicInteger timeout = new AtomicInteger(); - AtomicInteger rejections = new AtomicInteger(); - AtomicInteger echoed = new AtomicInteger(); - - CountDownLatch closed = new CountDownLatch(20); - for (int i=0;i<20;i++) - { - new Thread() - { - @Override - public void run() - { - try(Socket client = newClient();) - { - client.setSoTimeout(5000); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - - _manager.accept(server); - - // Write client to server - client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); - client.getOutputStream().flush(); - client.shutdownOutput(); - - // Verify echo server to client - for (char c : "HelloWorld".toCharArray()) - { - int b = client.getInputStream().read(); - assertTrue(b > 0); - assertEquals(c, (char)b); - } - assertEquals(-1,client.getInputStream().read()); - echoed.incrementAndGet(); - } - catch(SocketTimeoutException x) - { - x.printStackTrace(); - timeout.incrementAndGet(); - } - catch(Throwable x) - { - rejections.incrementAndGet(); - } - finally - { - closed.countDown(); - } - } - }.start(); - } - - // unblock the handling - latch.countDown(); - - // wait for all clients to complete or fail - closed.await(); - - // assert some clients must have been rejected - Assert.assertThat(rejections.get(),Matchers.greaterThan(0)); - // but not all of them - Assert.assertThat(rejections.get(),Matchers.lessThan(20)); - // none should have timed out - Assert.assertThat(timeout.get(),Matchers.equalTo(0)); - // and the rest should have worked - Assert.assertThat(echoed.get(),Matchers.equalTo(20-rejections.get())); - - // and the selector is still working for new requests - try(Socket client = newClient();) - { - client.setSoTimeout(5000); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - - _manager.accept(server); - - // Write client to server - client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); - client.getOutputStream().flush(); - client.shutdownOutput(); - - // Verify echo server to client - for (char c : "HelloWorld".toCharArray()) - { - int b = client.getInputStream().read(); - assertTrue(b > 0); - assertEquals(c, (char)b); - } - assertEquals(-1,client.getInputStream().read()); - } - - } -} diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointInterestsTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointInterestsTest.java similarity index 99% rename from jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointInterestsTest.java rename to jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointInterestsTest.java index 1a6ad99f879..04e17c9e4a0 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointInterestsTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointInterestsTest.java @@ -43,7 +43,7 @@ import org.junit.After; import org.junit.Assert; import org.junit.Test; -public class SelectChannelEndPointInterestsTest +public class SocketChannelEndPointInterestsTest { private QueuedThreadPool threadPool; private Scheduler scheduler; diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/EndPointTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointOpenCloseTest.java similarity index 81% rename from jetty-io/src/test/java/org/eclipse/jetty/io/EndPointTest.java rename to jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointOpenCloseTest.java index 794ab2d69a7..3ba75ca4684 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/EndPointTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointOpenCloseTest.java @@ -23,25 +23,51 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.nio.ByteBuffer; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; import org.eclipse.jetty.util.BufferUtil; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; -public abstract class EndPointTest +public class SocketChannelEndPointOpenCloseTest { - public static class EndPointPair + public static class EndPointPair { - public T client; - public T server; + public SocketChannelEndPoint client; + public SocketChannelEndPoint server; } - protected abstract EndPointPair newConnection() throws Exception; + static ServerSocketChannel connector; + @BeforeClass + public static void open() throws Exception + { + connector = ServerSocketChannel.open(); + connector.socket().bind(null); + } + + @AfterClass + public static void close() throws Exception + { + connector.close(); + connector=null; + } + + private EndPointPair newConnection() throws Exception + { + EndPointPair c = new EndPointPair(); + + c.client=new SocketChannelEndPoint(SocketChannel.open(connector.socket().getLocalSocketAddress()),null,null,null); + c.server=new SocketChannelEndPoint(connector.accept(),null,null,null); + return c; + } @Test public void testClientServerExchange() throws Exception { - EndPointPair c = newConnection(); + EndPointPair c = newConnection(); ByteBuffer buffer = BufferUtil.allocate(4096); // Client sends a request @@ -110,15 +136,12 @@ public abstract class EndPointTest assertTrue(c.client.isOutputShutdown()); assertFalse(c.server.isOpen()); assertTrue(c.server.isOutputShutdown()); - } - - @Test public void testClientClose() throws Exception { - EndPointPair c = newConnection(); + EndPointPair c = newConnection(); ByteBuffer buffer = BufferUtil.allocate(4096); c.client.flush(BufferUtil.toBuffer("request")); diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointTest.java index 691b7ee1e68..017104b7954 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointTest.java @@ -18,49 +18,832 @@ package org.eclipse.jetty.io; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; -import org.junit.AfterClass; -import org.junit.BeforeClass; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLSocket; -public class SocketChannelEndPointTest extends EndPointTest +import org.eclipse.jetty.io.ssl.SslConnection; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.toolchain.test.TestTracker; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.FutureCallback; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.eclipse.jetty.util.thread.Scheduler; +import org.eclipse.jetty.util.thread.TimerScheduler; +import org.hamcrest.Matchers; +import org.junit.After; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@SuppressWarnings("Duplicates") +@RunWith(Parameterized.class) +public class SocketChannelEndPointTest { - static ServerSocketChannel connector; + private static final Logger LOG = Log.getLogger(SocketChannelEndPoint.class); - @BeforeClass - public static void open() throws Exception + public interface Scenario { - connector = ServerSocketChannel.open(); - connector.socket().bind(null); + Socket newClient(ServerSocketChannel connector) throws IOException; + + Connection newConnection(SelectableChannel channel, EndPoint endPoint, Executor executor, AtomicInteger blockAt, AtomicInteger writeCount); + + boolean supportsHalfCloses(); } - @AfterClass - public static void close() throws Exception + @Parameterized.Parameters(name = "{0}") + public static List data() throws Exception { - connector.close(); - connector=null; + List ret = new ArrayList<>(); + + NormalScenario normalScenario = new NormalScenario(); + ret.add(new Object[]{normalScenario}); + ret.add(new Object[]{new SslScenario(normalScenario)}); + + return ret; } - @Override - protected EndPointPair newConnection() throws Exception - { - EndPointPair c = new EndPointPair<>(); + @Rule + public TestTracker tracker = new TestTracker(); - c.client=new SocketChannelEndPoint(SocketChannel.open(connector.socket().getLocalSocketAddress()),null,null,null); - c.server=new SocketChannelEndPoint(connector.accept(),null,null,null); - return c; + private final Scenario _scenario; + + private ServerSocketChannel _connector; + private QueuedThreadPool _threadPool; + private Scheduler _scheduler; + private SelectorManager _manager; + private volatile EndPoint _lastEndPoint; + private CountDownLatch _lastEndPointLatch; + + // Must be volatile or the test may fail spuriously + private AtomicInteger _blockAt = new AtomicInteger(0); + private AtomicInteger _writeCount = new AtomicInteger(1); + + public SocketChannelEndPointTest(Scenario scenario) throws Exception + { + _scenario = scenario; + _threadPool = new QueuedThreadPool(); + _scheduler = new TimerScheduler(); + _manager = new ScenarioSelectorManager(_threadPool, _scheduler); + + _lastEndPointLatch = new CountDownLatch(1); + _connector = ServerSocketChannel.open(); + _connector.socket().bind(null); + _scheduler.start(); + _threadPool.start(); + _manager.start(); } - @Override - public void testClientClose() throws Exception + @After + public void stopManager() throws Exception { - super.testClientClose(); + _scheduler.stop(); + _manager.stop(); + _threadPool.stop(); + _connector.close(); } - @Override - public void testClientServerExchange() throws Exception + @Test + public void testEcho() throws Exception { - super.testClientServerExchange(); + Socket client = _scenario.newClient(_connector); + + client.setSoTimeout(60000); + + SocketChannel server = _connector.accept(); + server.configureBlocking(false); + + _manager.accept(server); + + // Write client to server + client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); + + // Verify echo server to client + for (char c : "HelloWorld".toCharArray()) + { + int b = client.getInputStream().read(); + assertTrue(b > 0); + assertEquals(c, (char) b); + } + + // wait for read timeout + client.setSoTimeout(500); + long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + try + { + client.getInputStream().read(); + Assert.fail(); + } + catch (SocketTimeoutException e) + { + long duration = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start; + Assert.assertThat("timeout duration", duration, greaterThanOrEqualTo(400L)); + } + + // write then shutdown + client.getOutputStream().write("Goodbye Cruel TLS".getBytes(StandardCharsets.UTF_8)); + + // Verify echo server to client + for (char c : "Goodbye Cruel TLS".toCharArray()) + { + int b = client.getInputStream().read(); + Assert.assertThat("expect valid char integer", b, greaterThan(0)); + assertEquals("expect characters to be same", c, (char) b); + } + client.close(); + + for (int i = 0; i < 10; ++i) + { + if (server.isOpen()) + Thread.sleep(10); + else + break; + } + assertFalse(server.isOpen()); + } + + @Test + public void testShutdown() throws Exception + { + assumeTrue("Scenario supports half-close", _scenario.supportsHalfCloses()); + + Socket client = _scenario.newClient(_connector); + + client.setSoTimeout(500); + + SocketChannel server = _connector.accept(); + server.configureBlocking(false); + + _manager.accept(server); + + // Write client to server + client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); + + // Verify echo server to client + for (char c : "HelloWorld".toCharArray()) + { + int b = client.getInputStream().read(); + assertTrue(b > 0); + assertEquals(c, (char) b); + } + + // wait for read timeout + long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + try + { + client.getInputStream().read(); + Assert.fail(); + } + catch (SocketTimeoutException e) + { + assertTrue(TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start >= 400); + } + + // write then shutdown + client.getOutputStream().write("Goodbye Cruel TLS".getBytes(StandardCharsets.UTF_8)); + client.shutdownOutput(); + + // Verify echo server to client + for (char c : "Goodbye Cruel TLS".toCharArray()) + { + int b = client.getInputStream().read(); + assertTrue(b > 0); + assertEquals(c, (char) b); + } + + // Read close + assertEquals(-1, client.getInputStream().read()); + } + + @Test + public void testReadBlocked() throws Exception + { + Socket client = _scenario.newClient(_connector); + + SocketChannel server = _connector.accept(); + server.configureBlocking(false); + + _manager.accept(server); + + OutputStream clientOutputStream = client.getOutputStream(); + InputStream clientInputStream = client.getInputStream(); + + int specifiedTimeout = 1000; + client.setSoTimeout(specifiedTimeout); + + // Write 8 and cause block waiting for 10 + _blockAt.set(10); + clientOutputStream.write("12345678".getBytes(StandardCharsets.UTF_8)); + clientOutputStream.flush(); + + Assert.assertTrue(_lastEndPointLatch.await(1, TimeUnit.SECONDS)); + _lastEndPoint.setIdleTimeout(10 * specifiedTimeout); + Thread.sleep((11 * specifiedTimeout) / 10); + + long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + try + { + int b = clientInputStream.read(); + Assert.fail("Should have timed out waiting for a response, but read " + b); + } + catch (SocketTimeoutException e) + { + int elapsed = Long.valueOf(TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start).intValue(); + Assert.assertThat("Expected timeout", elapsed, greaterThanOrEqualTo(3 * specifiedTimeout / 4)); + } + + // write remaining characters + clientOutputStream.write("90ABCDEF".getBytes(StandardCharsets.UTF_8)); + clientOutputStream.flush(); + + // Verify echo server to client + for (char c : "1234567890ABCDEF".toCharArray()) + { + int b = clientInputStream.read(); + assertTrue(b > 0); + assertEquals(c, (char) b); + } + } + + @Test + public void testStress() throws Exception + { + Socket client = _scenario.newClient(_connector); + client.setSoTimeout(30000); + + SocketChannel server = _connector.accept(); + server.configureBlocking(false); + + _manager.accept(server); + final int writes = 200000; + + final byte[] bytes = "HelloWorld-".getBytes(StandardCharsets.UTF_8); + byte[] count = "0\n".getBytes(StandardCharsets.UTF_8); + BufferedOutputStream out = new BufferedOutputStream(client.getOutputStream()); + final CountDownLatch latch = new CountDownLatch(writes); + final InputStream in = new BufferedInputStream(client.getInputStream()); + final long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + out.write(bytes); + out.write(count); + out.flush(); + + Assert.assertTrue(_lastEndPointLatch.await(1, TimeUnit.SECONDS)); + _lastEndPoint.setIdleTimeout(5000); + + new Thread() + { + @Override + public void run() + { + Thread.currentThread().setPriority(MAX_PRIORITY); + long last = -1; + int count = -1; + try + { + while (latch.getCount() > 0) + { + // Verify echo server to client + for (byte b0 : bytes) + { + int b = in.read(); + Assert.assertThat(b, greaterThan(0)); + assertEquals(0xff & b0, b); + } + + count = 0; + int b = in.read(); + while (b > 0 && b != '\n') + { + count = count * 10 + (b - '0'); + b = in.read(); + } + last = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + + //if (latch.getCount()%1000==0) + // System.out.println(writes-latch.getCount()); + + latch.countDown(); + } + } + catch (Throwable e) + { + + long now = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + System.err.println("count=" + count); + System.err.println("latch=" + latch.getCount()); + System.err.println("time=" + (now - start)); + System.err.println("last=" + (now - last)); + System.err.println("endp=" + _lastEndPoint); + System.err.println("conn=" + _lastEndPoint.getConnection()); + + e.printStackTrace(); + } + } + }.start(); + + // Write client to server + for (int i = 1; i < writes; i++) + { + out.write(bytes); + out.write(Integer.toString(i).getBytes(StandardCharsets.ISO_8859_1)); + out.write('\n'); + if (i % 1000 == 0) + { + //System.err.println(i+"/"+writes); + out.flush(); + } + Thread.yield(); + } + out.flush(); + + long last = latch.getCount(); + while (!latch.await(5, TimeUnit.SECONDS)) + { + //System.err.println(latch.getCount()); + if (latch.getCount() == last) + Assert.fail(); + last = latch.getCount(); + } + + assertEquals(0, latch.getCount()); + } + + @Test + public void testWriteBlocked() throws Exception + { + Socket client = _scenario.newClient(_connector); + + client.setSoTimeout(10000); + + SocketChannel server = _connector.accept(); + server.configureBlocking(false); + + _manager.accept(server); + + // Write client to server + _writeCount.set(10000); + String data = "Now is the time for all good men to come to the aid of the party"; + client.getOutputStream().write(data.getBytes(StandardCharsets.UTF_8)); + BufferedInputStream in = new BufferedInputStream(client.getInputStream()); + + int byteNum = 0; + try + { + for (int i = 0; i < _writeCount.get(); i++) + { + if (i % 1000 == 0) + TimeUnit.MILLISECONDS.sleep(200); + + // Verify echo server to client + for (int j = 0; j < data.length(); j++) + { + char c = data.charAt(j); + int b = in.read(); + byteNum++; + assertTrue(b > 0); + assertEquals("test-" + i + "/" + j, c, (char) b); + } + + if (i == 0) + _lastEndPoint.setIdleTimeout(60000); + } + } + catch (SocketTimeoutException e) + { + System.err.println("SelectorManager.dump() = " + _manager.dump()); + LOG.warn("Server: " + server); + LOG.warn("Error reading byte #" + byteNum, e); + throw e; + } + + client.close(); + + for (int i = 0; i < 10; ++i) + { + if (server.isOpen()) + Thread.sleep(10); + else + break; + } + assertFalse(server.isOpen()); + } + + + // TODO make this test reliable + @Test + @Ignore + public void testRejectedExecution() throws Exception + { + _manager.stop(); + _threadPool.stop(); + + final CountDownLatch latch = new CountDownLatch(1); + + BlockingQueue q = new ArrayBlockingQueue<>(4); + _threadPool = new QueuedThreadPool(4, 4, 60000, q); + _manager = new SelectorManager(_threadPool, _scheduler, 1) + { + + @Override + protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey selectionKey) throws IOException + { + SocketChannelEndPoint endp = new SocketChannelEndPoint(channel, selector, selectionKey, getScheduler()); + _lastEndPoint = endp; + _lastEndPointLatch.countDown(); + return endp; + } + + @Override + public Connection newConnection(SelectableChannel channel, EndPoint endpoint, Object attachment) throws IOException + { + return new TestConnection(endpoint, latch, getExecutor(), _blockAt, _writeCount); + } + }; + + _threadPool.start(); + _manager.start(); + + AtomicInteger timeout = new AtomicInteger(); + AtomicInteger rejections = new AtomicInteger(); + AtomicInteger echoed = new AtomicInteger(); + + CountDownLatch closed = new CountDownLatch(20); + for (int i = 0; i < 20; i++) + { + new Thread() + { + @Override + public void run() + { + try (Socket client = _scenario.newClient(_connector);) + { + client.setSoTimeout(5000); + + SocketChannel server = _connector.accept(); + server.configureBlocking(false); + + _manager.accept(server); + + // Write client to server + client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); + client.getOutputStream().flush(); + client.shutdownOutput(); + + // Verify echo server to client + for (char c : "HelloWorld".toCharArray()) + { + int b = client.getInputStream().read(); + assertTrue(b > 0); + assertEquals(c, (char) b); + } + assertEquals(-1, client.getInputStream().read()); + echoed.incrementAndGet(); + } + catch (SocketTimeoutException x) + { + x.printStackTrace(); + timeout.incrementAndGet(); + } + catch (Throwable x) + { + rejections.incrementAndGet(); + } + finally + { + closed.countDown(); + } + } + }.start(); + } + + // unblock the handling + latch.countDown(); + + // wait for all clients to complete or fail + closed.await(); + + // assert some clients must have been rejected + Assert.assertThat(rejections.get(), Matchers.greaterThan(0)); + // but not all of them + Assert.assertThat(rejections.get(), Matchers.lessThan(20)); + // none should have timed out + Assert.assertThat(timeout.get(), Matchers.equalTo(0)); + // and the rest should have worked + Assert.assertThat(echoed.get(), Matchers.equalTo(20 - rejections.get())); + + // and the selector is still working for new requests + try (Socket client = _scenario.newClient(_connector)) + { + client.setSoTimeout(5000); + + SocketChannel server = _connector.accept(); + server.configureBlocking(false); + + _manager.accept(server); + + // Write client to server + client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); + client.getOutputStream().flush(); + client.shutdownOutput(); + + // Verify echo server to client + for (char c : "HelloWorld".toCharArray()) + { + int b = client.getInputStream().read(); + assertTrue(b > 0); + assertEquals(c, (char) b); + } + assertEquals(-1, client.getInputStream().read()); + } + } + + public class ScenarioSelectorManager extends SelectorManager + { + protected ScenarioSelectorManager(Executor executor, Scheduler scheduler) + { + super(executor, scheduler); + } + + protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey key) throws IOException + { + SocketChannelEndPoint endp = new SocketChannelEndPoint(channel, selector, key, getScheduler()); + endp.setIdleTimeout(60000); + _lastEndPoint = endp; + _lastEndPointLatch.countDown(); + return endp; + } + + @Override + public Connection newConnection(SelectableChannel channel, EndPoint endpoint, Object attachment) throws IOException + { + return _scenario.newConnection(channel, endpoint, getExecutor(), _blockAt, _writeCount); + } + } + + public static class NormalScenario implements Scenario + { + @Override + public Socket newClient(ServerSocketChannel connector) throws IOException + { + return new Socket(connector.socket().getInetAddress(), connector.socket().getLocalPort()); + } + + @Override + public Connection newConnection(SelectableChannel channel, EndPoint endpoint, Executor executor, AtomicInteger blockAt, AtomicInteger writeCount) + { + return new TestConnection(endpoint, executor, blockAt, writeCount); + } + + @Override + public boolean supportsHalfCloses() + { + return true; + } + + @Override + public String toString() + { + return "normal"; + } + } + + public static class SslScenario implements Scenario + { + private final NormalScenario _normalScenario; + private final SslContextFactory __sslCtxFactory = new SslContextFactory(); + private final ByteBufferPool __byteBufferPool = new MappedByteBufferPool(); + + public SslScenario(NormalScenario normalScenario) throws Exception + { + _normalScenario = normalScenario; + File keystore = MavenTestingUtils.getTestResourceFile("keystore"); + __sslCtxFactory.setKeyStorePath(keystore.getAbsolutePath()); + __sslCtxFactory.setKeyStorePassword("storepwd"); + __sslCtxFactory.setKeyManagerPassword("keypwd"); + __sslCtxFactory.setEndpointIdentificationAlgorithm(""); + __sslCtxFactory.start(); + } + + @Override + public Socket newClient(ServerSocketChannel connector) throws IOException + { + SSLSocket socket = __sslCtxFactory.newSslSocket(); + socket.connect(connector.socket().getLocalSocketAddress()); + return socket; + } + + @Override + public Connection newConnection(SelectableChannel channel, EndPoint endpoint, Executor executor, AtomicInteger blockAt, AtomicInteger writeCount) + { + SSLEngine engine = __sslCtxFactory.newSSLEngine(); + engine.setUseClientMode(false); + SslConnection sslConnection = new SslConnection(__byteBufferPool, executor, endpoint, engine); + sslConnection.setRenegotiationAllowed(__sslCtxFactory.isRenegotiationAllowed()); + sslConnection.setRenegotiationLimit(__sslCtxFactory.getRenegotiationLimit()); + Connection appConnection = _normalScenario.newConnection(channel, sslConnection.getDecryptedEndPoint(), executor, blockAt, writeCount); + sslConnection.getDecryptedEndPoint().setConnection(appConnection); + return sslConnection; + } + + @Override + public boolean supportsHalfCloses() + { + return false; + } + + @Override + public String toString() + { + return "ssl"; + } + } + + @SuppressWarnings("Duplicates") + public static class TestConnection extends AbstractConnection + { + private static final Logger LOG = Log.getLogger(TestConnection.class); + + volatile FutureCallback _blockingRead; + final AtomicInteger _blockAt; + final AtomicInteger _writeCount; + // volatile int _blockAt = 0; + ByteBuffer _in = BufferUtil.allocate(32 * 1024); + ByteBuffer _out = BufferUtil.allocate(32 * 1024); + long _last = -1; + final CountDownLatch _latch; + + public TestConnection(EndPoint endp, Executor executor, AtomicInteger blockAt, AtomicInteger writeCount) + { + super(endp, executor); + _latch = null; + this._blockAt = blockAt; + this._writeCount = writeCount; + } + + public TestConnection(EndPoint endp, CountDownLatch latch, Executor executor, AtomicInteger blockAt, AtomicInteger writeCount) + { + super(endp, executor); + _latch = latch; + this._blockAt = blockAt; + this._writeCount = writeCount; + } + + @Override + public void onOpen() + { + super.onOpen(); + fillInterested(); + } + + @Override + public void onFillInterestedFailed(Throwable cause) + { + Callback blocking = _blockingRead; + if (blocking != null) + { + _blockingRead = null; + blocking.failed(cause); + return; + } + super.onFillInterestedFailed(cause); + } + + @Override + public void onFillable() + { + if (_latch != null) + { + try + { + _latch.await(); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + + Callback blocking = _blockingRead; + if (blocking != null) + { + _blockingRead = null; + blocking.succeeded(); + return; + } + + EndPoint _endp = getEndPoint(); + try + { + _last = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + boolean progress = true; + while (progress) + { + progress = false; + + // Fill the input buffer with everything available + BufferUtil.compact(_in); + if (BufferUtil.isFull(_in)) + throw new IllegalStateException("FULL " + BufferUtil.toDetailString(_in)); + int filled = _endp.fill(_in); + if (filled > 0) + progress = true; + + // If the tests wants to block, then block + while (_blockAt.get() > 0 && _endp.isOpen() && _in.remaining() < _blockAt.get()) + { + FutureCallback future = _blockingRead = new FutureCallback(); + fillInterested(); + future.get(); + filled = _endp.fill(_in); + progress |= filled > 0; + } + + // Copy to the out buffer + if (BufferUtil.hasContent(_in) && BufferUtil.append(_out, _in) > 0) + progress = true; + + // Blocking writes + if (BufferUtil.hasContent(_out)) + { + ByteBuffer out = _out.duplicate(); + BufferUtil.clear(_out); + for (int i = 0; i < _writeCount.get(); i++) + { + FutureCallback blockingWrite = new FutureCallback(); + _endp.write(blockingWrite, out.asReadOnlyBuffer()); + blockingWrite.get(); + } + progress = true; + } + + // are we done? + if (_endp.isInputShutdown()) + _endp.shutdownOutput(); + } + + if (_endp.isOpen()) + fillInterested(); + } + catch (ExecutionException e) + { + // Timeout does not close, so echo exception then shutdown + try + { + FutureCallback blockingWrite = new FutureCallback(); + _endp.write(blockingWrite, BufferUtil.toBuffer("EE: " + BufferUtil.toString(_in))); + blockingWrite.get(); + _endp.shutdownOutput(); + } + catch (Exception e2) + { + // e2.printStackTrace(); + } + } + catch (InterruptedException | EofException e) + { + LOG.info(e); + } + catch (Exception e) + { + LOG.warn(e); + } + } } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointSslTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SslEngineBehaviorTest.java similarity index 56% rename from jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointSslTest.java rename to jetty-io/src/test/java/org/eclipse/jetty/io/SslEngineBehaviorTest.java index da7139002aa..2113f0feabe 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointSslTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SslEngineBehaviorTest.java @@ -18,110 +18,46 @@ package org.eclipse.jetty.io; -import java.io.File; -import java.io.IOException; -import java.net.Socket; -import java.nio.ByteBuffer; -import java.nio.channels.SelectableChannel; -import java.nio.channels.SocketChannel; - -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLEngineResult.HandshakeStatus; -import javax.net.ssl.SSLSocket; - -import org.eclipse.jetty.io.ssl.SslConnection; -import org.eclipse.jetty.toolchain.test.JDK; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.toolchain.test.annotation.Stress; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; - import static org.hamcrest.Matchers.greaterThan; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import java.io.File; +import java.nio.ByteBuffer; -public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; + +import org.eclipse.jetty.toolchain.test.JDK; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.BeforeClass; +import org.junit.Test; + +public class SslEngineBehaviorTest { - private static SslContextFactory __sslCtxFactory=new SslContextFactory(); - private static ByteBufferPool __byteBufferPool = new MappedByteBufferPool(); + private static SslContextFactory sslCtxFactory; @BeforeClass - public static void initSslEngine() throws Exception + public static void startSsl() throws Exception { + sslCtxFactory = new SslContextFactory(); File keystore = MavenTestingUtils.getTestResourceFile("keystore"); - __sslCtxFactory.setKeyStorePath(keystore.getAbsolutePath()); - __sslCtxFactory.setKeyStorePassword("storepwd"); - __sslCtxFactory.setKeyManagerPassword("keypwd"); - __sslCtxFactory.setEndpointIdentificationAlgorithm(""); - __sslCtxFactory.start(); + sslCtxFactory.setKeyStorePath(keystore.getAbsolutePath()); + sslCtxFactory.setKeyStorePassword("storepwd"); + sslCtxFactory.setKeyManagerPassword("keypwd"); + sslCtxFactory.setEndpointIdentificationAlgorithm(""); + sslCtxFactory.start(); } - @Override - protected Socket newClient() throws IOException + @AfterClass + public static void stopSsl() throws Exception { - SSLSocket socket = __sslCtxFactory.newSslSocket(); - socket.connect(_connector.socket().getLocalSocketAddress()); - return socket; - } - - @Override - protected Connection newConnection(SelectableChannel channel, EndPoint endpoint) - { - SSLEngine engine = __sslCtxFactory.newSSLEngine(); - engine.setUseClientMode(false); - SslConnection sslConnection = new SslConnection(__byteBufferPool, _threadPool, endpoint, engine); - sslConnection.setRenegotiationAllowed(__sslCtxFactory.isRenegotiationAllowed()); - sslConnection.setRenegotiationLimit(__sslCtxFactory.getRenegotiationLimit()); - Connection appConnection = super.newConnection(channel,sslConnection.getDecryptedEndPoint()); - sslConnection.getDecryptedEndPoint().setConnection(appConnection); - return sslConnection; - } - - @Test - @Override - public void testEcho() throws Exception - { - super.testEcho(); - } - - @Ignore // SSL does not do half closes - @Override - public void testShutdown() throws Exception - { - } - - @Test - @Override - public void testWriteBlocked() throws Exception - { - super.testWriteBlocked(); - } - - @Override - public void testReadBlocked() throws Exception - { - super.testReadBlocked(); - } - - @Override - public void testIdle() throws Exception - { - super.testIdle(); - } - - @Test - @Override - @Stress("Requires a relatively idle (network wise) environment") - public void testStress() throws Exception - { - super.testStress(); + sslCtxFactory.stop(); } @Test @@ -129,8 +65,8 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest { Assume.assumeFalse(JDK.IS_9); - SSLEngine server = __sslCtxFactory.newSSLEngine(); - SSLEngine client = __sslCtxFactory.newSSLEngine(); + SSLEngine server = sslCtxFactory.newSSLEngine(); + SSLEngine client = sslCtxFactory.newSSLEngine(); ByteBuffer netC2S = ByteBuffer.allocate(server.getSession().getPacketBufferSize()); ByteBuffer netS2C = ByteBuffer.allocate(server.getSession().getPacketBufferSize()); @@ -143,7 +79,7 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest // start the client client.setUseClientMode(true); client.beginHandshake(); - Assert.assertEquals(HandshakeStatus.NEED_WRAP,client.getHandshakeStatus()); + Assert.assertEquals(SSLEngineResult.HandshakeStatus.NEED_WRAP,client.getHandshakeStatus()); // what if we try an unwrap? netS2C.flip(); @@ -152,7 +88,7 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest assertEquals(SSLEngineResult.Status.OK,result.getStatus()); assertEquals(0,result.bytesConsumed()); assertEquals(0,result.bytesProduced()); - assertEquals(HandshakeStatus.NEED_WRAP,result.getHandshakeStatus()); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_WRAP,result.getHandshakeStatus()); netS2C.clear(); // do the needed WRAP of empty buffer @@ -161,14 +97,14 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest assertEquals(SSLEngineResult.Status.OK,result.getStatus()); assertEquals(0,result.bytesConsumed()); assertThat(result.bytesProduced(),greaterThan(0)); - assertEquals(HandshakeStatus.NEED_UNWRAP,result.getHandshakeStatus()); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP,result.getHandshakeStatus()); netC2S.flip(); assertEquals(netC2S.remaining(),result.bytesProduced()); // start the server server.setUseClientMode(false); server.beginHandshake(); - Assert.assertEquals(HandshakeStatus.NEED_UNWRAP,server.getHandshakeStatus()); + Assert.assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP,server.getHandshakeStatus()); // what if we try a needless wrap? serverOut.put(BufferUtil.toBuffer("Hello World")); @@ -178,14 +114,14 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest assertEquals(SSLEngineResult.Status.OK,result.getStatus()); assertEquals(0,result.bytesConsumed()); assertEquals(0,result.bytesProduced()); - assertEquals(HandshakeStatus.NEED_UNWRAP,result.getHandshakeStatus()); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP,result.getHandshakeStatus()); // Do the needed unwrap, to an empty buffer result=server.unwrap(netC2S,BufferUtil.EMPTY_BUFFER); assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW,result.getStatus()); assertEquals(0,result.bytesConsumed()); assertEquals(0,result.bytesProduced()); - assertEquals(HandshakeStatus.NEED_UNWRAP,result.getHandshakeStatus()); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP,result.getHandshakeStatus()); // Do the needed unwrap, to a full buffer serverIn.position(serverIn.limit()); @@ -193,7 +129,7 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW,result.getStatus()); assertEquals(0,result.bytesConsumed()); assertEquals(0,result.bytesProduced()); - assertEquals(HandshakeStatus.NEED_UNWRAP,result.getHandshakeStatus()); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP,result.getHandshakeStatus()); // Do the needed unwrap, to an empty buffer serverIn.clear(); @@ -201,10 +137,10 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest assertEquals(SSLEngineResult.Status.OK,result.getStatus()); assertThat(result.bytesConsumed(),greaterThan(0)); assertEquals(0,result.bytesProduced()); - assertEquals(HandshakeStatus.NEED_TASK,result.getHandshakeStatus()); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_TASK,result.getHandshakeStatus()); server.getDelegatedTask().run(); - assertEquals(HandshakeStatus.NEED_WRAP,server.getHandshakeStatus()); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_WRAP,server.getHandshakeStatus()); } } diff --git a/jetty-jaas/src/main/config/modules/jaas.mod b/jetty-jaas/src/main/config/modules/jaas.mod index 26c68fff54b..d8c78b63869 100644 --- a/jetty-jaas/src/main/config/modules/jaas.mod +++ b/jetty-jaas/src/main/config/modules/jaas.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enable JAAS for deployed webapplications. diff --git a/jetty-jaspi/src/main/config/modules/jaspi.mod b/jetty-jaspi/src/main/config/modules/jaspi.mod index 0d552730346..372c00e07bd 100644 --- a/jetty-jaspi/src/main/config/modules/jaspi.mod +++ b/jetty-jaspi/src/main/config/modules/jaspi.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enable JASPI authentication for deployed webapplications. diff --git a/jetty-jmx/src/main/config/modules/jmx-remote.mod b/jetty-jmx/src/main/config/modules/jmx-remote.mod index 438f3368ef9..bf6b200471c 100644 --- a/jetty-jmx/src/main/config/modules/jmx-remote.mod +++ b/jetty-jmx/src/main/config/modules/jmx-remote.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables remote RMI access to JMX diff --git a/jetty-jmx/src/main/config/modules/jmx.mod b/jetty-jmx/src/main/config/modules/jmx.mod index a59c6dd9c1b..969b5f167fb 100644 --- a/jetty-jmx/src/main/config/modules/jmx.mod +++ b/jetty-jmx/src/main/config/modules/jmx.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables JMX instrumentation for server beans and enables JMX agent. diff --git a/jetty-jndi/src/main/config/modules/jndi.mod b/jetty-jndi/src/main/config/modules/jndi.mod index 39fc8069c0d..989a37cc883 100644 --- a/jetty-jndi/src/main/config/modules/jndi.mod +++ b/jetty-jndi/src/main/config/modules/jndi.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Adds the Jetty JNDI implementation to the classpath. diff --git a/jetty-jspc-maven-plugin/src/it/settings.xml b/jetty-jspc-maven-plugin/src/it/settings.xml new file mode 100644 index 00000000000..d64bdb89034 --- /dev/null +++ b/jetty-jspc-maven-plugin/src/it/settings.xml @@ -0,0 +1,36 @@ + + + + + + it-repo + + true + + + + local.central + @localRepositoryUrl@ + + true + + + true + + + + + + local.central + @localRepositoryUrl@ + + true + + + true + + + + + + diff --git a/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/invoker.properties b/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/invoker.properties new file mode 100644 index 00000000000..8a7cae8ef84 --- /dev/null +++ b/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/invoker.properties @@ -0,0 +1,3 @@ +invoker.goals = test -fae +invoker.buildResult = failure +invoker.debug = true diff --git a/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/pom.xml b/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/pom.xml new file mode 100644 index 00000000000..f6c1416e8e8 --- /dev/null +++ b/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + org.eclipse.jetty.its.jspc + simple-jsp-fail + 0.0.1-SNAPSHOT + pom + + Jetty :: Simple Jsp Fail + + + UTF-8 + UTF-8 + 1.8 + 3.0.0 + @project.version@ + + + + + + + org.eclipse.jetty + jetty-jspc-maven-plugin + ${jetty.version} + + + + jspc + + compile + + src/main/jsp + + + + + + + + diff --git a/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/postbuild.groovy b/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/postbuild.groovy new file mode 100644 index 00000000000..f7e5d5e8bc1 --- /dev/null +++ b/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/postbuild.groovy @@ -0,0 +1,3 @@ + + +System.out.println( "running postbuild.groovy" ) diff --git a/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/src/main/jsp/foo.jsp b/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/src/main/jsp/foo.jsp new file mode 100644 index 00000000000..00b636ccd93 --- /dev/null +++ b/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/src/main/jsp/foo.jsp @@ -0,0 +1,23 @@ + +<%@ page import="java.util.Enumeration" %> + +

JSP Dump

+ + + + + + +<% + Enumeration e =request.getParameterNames(); + while(e.hasMoreElements()) + { + String name = (String)e.nextElement(); +%> + + + +<% } %> + +
Request URI:<%= request.getFoo() %>
ServletPath:<%= request.getServletPath() %>
PathInfo:<%= request.getPathInfo() %>
getParameter("<%= name %>")<%= request.getParameter(name) %>
+ diff --git a/jetty-jspc-maven-plugin/src/it/simple-jsp/invoker.properties b/jetty-jspc-maven-plugin/src/it/simple-jsp/invoker.properties new file mode 100644 index 00000000000..df6cbf2d0bc --- /dev/null +++ b/jetty-jspc-maven-plugin/src/it/simple-jsp/invoker.properties @@ -0,0 +1,2 @@ +invoker.goals = test -fae +invoker.debug = true diff --git a/jetty-jspc-maven-plugin/src/it/simple-jsp/pom.xml b/jetty-jspc-maven-plugin/src/it/simple-jsp/pom.xml new file mode 100644 index 00000000000..5b1bb09a31b --- /dev/null +++ b/jetty-jspc-maven-plugin/src/it/simple-jsp/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + + org.eclipse.jetty.its.jspc + simple-jsp + 0.0.1-SNAPSHOT + pom + + Jetty :: Simple Jsp + + + UTF-8 + UTF-8 + 1.8 + @project.version@ + + + + + + + org.eclipse.jetty + jetty-jspc-maven-plugin + ${jetty.version} + + + + jspc + + compile + + + + + + + diff --git a/jetty-jspc-maven-plugin/src/it/simple-jsp/postbuild.groovy b/jetty-jspc-maven-plugin/src/it/simple-jsp/postbuild.groovy new file mode 100644 index 00000000000..f7e5d5e8bc1 --- /dev/null +++ b/jetty-jspc-maven-plugin/src/it/simple-jsp/postbuild.groovy @@ -0,0 +1,3 @@ + + +System.out.println( "running postbuild.groovy" ) diff --git a/jetty-jspc-maven-plugin/src/it/simple-jsp/src/main/webapp/foo.jsp b/jetty-jspc-maven-plugin/src/it/simple-jsp/src/main/webapp/foo.jsp new file mode 100644 index 00000000000..fb73b0b0002 --- /dev/null +++ b/jetty-jspc-maven-plugin/src/it/simple-jsp/src/main/webapp/foo.jsp @@ -0,0 +1,23 @@ + +<%@ page import="java.util.Enumeration" %> + +

JSP Dump

+ + + + + + +<% + Enumeration e =request.getParameterNames(); + while(e.hasMoreElements()) + { + String name = (String)e.nextElement(); +%> + + + +<% } %> + +
Request URI:<%= request.getRequestURI() %>
ServletPath:<%= request.getServletPath() %>
PathInfo:<%= request.getPathInfo() %>
getParameter("<%= name %>")<%= request.getParameter(name) %>
+ diff --git a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/pom.xml b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/pom.xml index c43b9f0e7b1..ed07bd37fe6 100644 --- a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/pom.xml @@ -65,7 +65,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.20 + @surefireVersion@ ${jetty.port.file} diff --git a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/etc/test-jetty.xml b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/etc/test-jetty.xml index fbdc1a01394..5062d20c4fc 100644 --- a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/etc/test-jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/etc/test-jetty.xml @@ -1,5 +1,5 @@ - + diff --git a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/modules/testmod.mod b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/modules/testmod.mod index e1ee0758792..e451df43f4a 100644 --- a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/modules/testmod.mod +++ b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/modules/testmod.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables test setup diff --git a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/pom.xml b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/pom.xml index aee069f4651..40f2b144fe4 100644 --- a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/pom.xml @@ -72,7 +72,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.20 + @surefireVersion@ ${jetty.port.file} diff --git a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/config/jetty.xml index 0b843c05a99..c38bcced0e1 100644 --- a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -1,5 +1,5 @@ - + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/pom.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/pom.xml index 2d8381239d5..df71841c32c 100644 --- a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/pom.xml @@ -68,7 +68,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.20 + @surefireVersion@ ${jetty.port.file} diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/config/jetty.xml index 0b843c05a99..c38bcced0e1 100644 --- a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -1,5 +1,5 @@ - + diff --git a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/config/jetty.xml index 0b843c05a99..c38bcced0e1 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -1,5 +1,5 @@ - + diff --git a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/config/jetty.xml index 0b843c05a99..c38bcced0e1 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -1,5 +1,5 @@ - + diff --git a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/pom.xml b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/pom.xml index 14bb7e933ef..7c0f1bc1b75 100644 --- a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/pom.xml @@ -64,7 +64,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.20 + @surefireVersion@ ${jetty.port.file} diff --git a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/config/jetty.xml index 0b843c05a99..c38bcced0e1 100644 --- a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -1,5 +1,5 @@ - + diff --git a/jetty-maven-plugin/src/main/resources/maven.mod b/jetty-maven-plugin/src/main/resources/maven.mod index ee54ce0ebbb..0fd52cdeb80 100644 --- a/jetty-maven-plugin/src/main/resources/maven.mod +++ b/jetty-maven-plugin/src/main/resources/maven.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables an unassembled maven webapp to run in a jetty distro diff --git a/jetty-memcached/jetty-memcached-sessions/src/main/config/modules/sessions/session-data-cache/xmemcached.mod b/jetty-memcached/jetty-memcached-sessions/src/main/config/modules/sessions/session-data-cache/xmemcached.mod index e1e71817158..0618c02950a 100644 --- a/jetty-memcached/jetty-memcached-sessions/src/main/config/modules/sessions/session-data-cache/xmemcached.mod +++ b/jetty-memcached/jetty-memcached-sessions/src/main/config/modules/sessions/session-data-cache/xmemcached.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Memcache cache for SessionData diff --git a/jetty-monitor/README.TXT b/jetty-monitor/README.TXT deleted file mode 100644 index 72c7da114f9..00000000000 --- a/jetty-monitor/README.TXT +++ /dev/null @@ -1,13 +0,0 @@ -The ThreadMonitor is distributed as part of the jetty-monitor module. - -In order to start ThreadMonitor when server starts up, the following command line should be used. - - java -jar start.jar OPTIONS=monitor jetty-monitor.xml - -To run ThreadMonitor on a Jetty installation that doesn't include jetty-monitor module, the jetty-monitor-[version].jar file needs to be copied into ${jetty.home}/lib/ext directory, and jetty-monitor.xml configuration file needs to be copied into ${jetty.home}/etc directory. Subsequently, the following command line should be used. - - java -jar start.jar etc/jetty-monitor.xml - -If running Jetty on Java VM version 1.5, the -Dcom.sun.management.jmxremote option should be added to the command lines above in order to enable the JMX agent. - -In order to log CPU utilization for threads that are above specified threshold, you need to follow instructions inside jetty-monitor.xml configuration file. \ No newline at end of file diff --git a/jetty-monitor/pom.xml b/jetty-monitor/pom.xml deleted file mode 100644 index 6824d25e766..00000000000 --- a/jetty-monitor/pom.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - org.eclipse.jetty - jetty-project - 10.0.0-SNAPSHOT - - 4.0.0 - jetty-monitor - Jetty :: Monitoring - http://www.eclipse.org/jetty - Performance monitoring artifact for jetty. - - ${project.groupId}.monitor - - - - - org.apache.maven.plugins - maven-surefire-plugin - - always - - - - org.codehaus.mojo - findbugs-maven-plugin - - org.eclipse.jetty.monitor.* - - - - - - - org.eclipse.jetty - jetty-util - ${project.version} - - - org.eclipse.jetty - jetty-io - ${project.version} - - - org.eclipse.jetty - jetty-http - ${project.version} - - - org.eclipse.jetty - jetty-xml - ${project.version} - - - org.eclipse.jetty - jetty-client - ${project.version} - - - org.eclipse.jetty - jetty-jmx - ${project.version} - test - - - - org.eclipse.jetty - jetty-server - ${project.version} - test - - - org.eclipse.jetty.toolchain - jetty-test-helper - test - - - diff --git a/jetty-monitor/src/main/config/etc/jetty-monitor.xml b/jetty-monitor/src/main/config/etc/jetty-monitor.xml deleted file mode 100644 index a8f663367e4..00000000000 --- a/jetty-monitor/src/main/config/etc/jetty-monitor.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - 2000 - 90 - 3 - 2 - - - - - - - - - - - - - diff --git a/jetty-monitor/src/main/config/modules/monitor.mod b/jetty-monitor/src/main/config/modules/monitor.mod deleted file mode 100644 index f1fa81f98c1..00000000000 --- a/jetty-monitor/src/main/config/modules/monitor.mod +++ /dev/null @@ -1,13 +0,0 @@ -[description] -Enables the Jetty Monitor Module to periodically -check/publish JMX parameters of the server. - -[depend] -server -client - -[lib] -lib/monitor/jetty-monitor-${jetty.version}.jar - -[xml] -etc/jetty-monitor.xml diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/JMXMonitor.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/JMXMonitor.java deleted file mode 100644 index 36db34f45f1..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/JMXMonitor.java +++ /dev/null @@ -1,193 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor; - -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; - -import javax.management.MBeanServerConnection; - -import org.eclipse.jetty.monitor.jmx.MonitorAction; -import org.eclipse.jetty.monitor.jmx.MonitorTask; -import org.eclipse.jetty.monitor.jmx.ServiceConnection; -import org.eclipse.jetty.xml.XmlConfiguration; - -/** - * JMXMonitor - *

- * Performs monitoring of the values of the attributes of MBeans - * and executes specified actions as well as sends notifications - * of the specified events that have occurred. - */ -public class JMXMonitor -{ - private static JMXMonitor __monitor = new JMXMonitor(); - - private String _serverUrl; - private ServiceConnection _serviceConnection; - - private Set _actions = new HashSet(); - - /* ------------------------------------------------------------ */ - /** - * Constructs a JMXMonitor instance. Used for XML Configuration. - * - * !! DO NOT INSTANTIATE EXPLICITLY !! - */ - public JMXMonitor() {} - - /* ------------------------------------------------------------ */ - /** - * Adds monitor actions to the monitor - * - * @param actions monitor actions to add - * @return true if successful - */ - public boolean addActions(MonitorAction... actions) - { - return getInstance().add(actions); - } - - /* ------------------------------------------------------------ */ - /** - * Removes monitor actions from the monitor - * - * @param actions monitor actions to remove - * @return true if successful - */ - public boolean removeActions(MonitorAction... actions) - { - return getInstance().remove(actions); - } - - /* ------------------------------------------------------------ */ - /** - * Sets the JMX server URL - * - * @param url URL of the JMX server - */ - public void setUrl(String url) - { - getInstance().set(url); - } - - public MBeanServerConnection getConnection() - throws IOException - { - return getInstance().get(); - } - - public static JMXMonitor getInstance() - { - return __monitor; - } - - public static boolean addMonitorActions(MonitorAction... actions) - { - return getInstance().add(actions); - } - - public static boolean removeMonitorActions(MonitorAction... actions) - { - return getInstance().remove(actions); - } - - public static void setServiceUrl(String url) - { - getInstance().set(url); - } - - /* ------------------------------------------------------------ */ - /** - * Retrieves a connection to JMX service - * - * @return server connection - * @throws IOException if unable to obtain server connection - */ - public static MBeanServerConnection getServiceConnection() - throws IOException - { - return getInstance().getConnection(); - } - - public static void main(final String args[]) throws Exception - { - XmlConfiguration.main(args); - } - - private synchronized boolean add(MonitorAction... actions) - { - boolean result = true; - - for (MonitorAction action : actions) - { - if (!_actions.add(action)) - { - result = false; - } - else - { - MonitorTask.schedule(action); - } - } - - return result; - } - - private synchronized boolean remove(MonitorAction... actions) - { - boolean result = true; - - for (MonitorAction action : actions) - { - if (!_actions.remove(action)) - { - result = false; - } - - MonitorTask.cancel(action); - } - - return result; - } - - private synchronized void set(String url) - { - _serverUrl = url; - - if (_serviceConnection != null) - { - _serviceConnection.disconnect(); - _serviceConnection = null; - } - } - - private synchronized MBeanServerConnection get() - throws IOException - { - if (_serviceConnection == null) - { - _serviceConnection = new ServiceConnection(_serverUrl); - _serviceConnection.connect(); - } - - return _serviceConnection.getConnection(); - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/ThreadMonitor.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/ThreadMonitor.java deleted file mode 100644 index 02f77268962..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/ThreadMonitor.java +++ /dev/null @@ -1,610 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor; - -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadMXBean; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.eclipse.jetty.monitor.thread.ThreadMonitorException; -import org.eclipse.jetty.monitor.thread.ThreadMonitorInfo; -import org.eclipse.jetty.util.annotation.ManagedObject; -import org.eclipse.jetty.util.component.AbstractLifeCycle; -import org.eclipse.jetty.util.component.Dumpable; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -@ManagedObject("Busy Thread Monitor") -public class ThreadMonitor extends AbstractLifeCycle implements Runnable -{ - private static final Logger LOG = Log.getLogger(ThreadMonitor.class); - - private int _scanInterval; - private int _logInterval; - private int _busyThreshold; - private int _logThreshold; - private int _stackDepth; - private int _trailLength; - - private ThreadMXBean _threadBean; - - private Thread _runner; - private Logger _logger; - private volatile boolean _done = true; - private Dumpable _dumpable; - - private Map _monitorInfo; - - /* ------------------------------------------------------------ */ - /** - * Instantiates a new thread monitor. - * - * @throws Exception if unable to instantiate thread monitor - */ - public ThreadMonitor() throws Exception - { - this(5000); - } - - /* ------------------------------------------------------------ */ - /** - * Instantiates a new thread monitor. - * - * @param intervalMs scan interval - * @throws Exception if unable to instantiate thread monitor - */ - public ThreadMonitor(int intervalMs) throws Exception - { - this(intervalMs, 95); - } - - /* ------------------------------------------------------------ */ - /** - * Instantiates a new thread monitor. - * - * @param intervalMs scan interval - * @param threshold busy threshold - * @throws Exception if unable to instantiate thread monitor - */ - public ThreadMonitor(int intervalMs, int threshold) throws Exception - { - this(intervalMs, threshold, 3); - } - - /* ------------------------------------------------------------ */ - /** - * Instantiates a new thread monitor. - * - * @param intervalMs scan interval - * @param threshold busy threshold - * @param depth stack compare depth - * @throws Exception if unable to instantiate thread monitor - */ - public ThreadMonitor(int intervalMs, int threshold, int depth) throws Exception - { - this(intervalMs, threshold, depth, 3); - } - - /* ------------------------------------------------------------ */ - /** - * Instantiates a new thread monitor. - * - * @param intervalMs scan interval - * @param threshold busy threshold - * @param depth stack compare depth - * @param trail length of stack trail - * @throws Exception if unable to instantiate thread monitor - */ - public ThreadMonitor(int intervalMs, int threshold, int depth, int trail) throws Exception - { - _scanInterval = intervalMs; - _busyThreshold = threshold; - _stackDepth = depth; - _trailLength = trail; - - _logger = Log.getLogger(ThreadMonitor.class.getName()); - _monitorInfo = new HashMap(); - - init(); - } - - /* ------------------------------------------------------------ */ - /** - * Gets the scan interval. - * - * @return the scan interval - */ - public int getScanInterval() - { - return _scanInterval; - } - - /* ------------------------------------------------------------ */ - /** - * Sets the scan interval. - * - * @param ms the new scan interval - */ - public void setScanInterval(int ms) - { - _scanInterval = ms; - } - - /* ------------------------------------------------------------ */ - /** - * Gets the log interval. - * - * @return the log interval - */ - public int getLogInterval() - { - return _logInterval; - } - - /* ------------------------------------------------------------ */ - /** - * Sets the log interval. - * - * @param ms the new log interval - */ - public void setLogInterval(int ms) - { - _logInterval = ms; - } - - /* ------------------------------------------------------------ */ - /** - * Gets the busy threshold. - * - * @return the busy threshold - */ - public int getBusyThreshold() - { - return _busyThreshold; - } - - /* ------------------------------------------------------------ */ - /** - * Sets the busy threshold. - * - * @param percent the new busy threshold - */ - public void setBusyThreshold(int percent) - { - _busyThreshold = percent; - } - - /* ------------------------------------------------------------ */ - /** - * Gets the log threshold. - * - * @return the log threshold - */ - public int getLogThreshold() - { - return _logThreshold; - } - - /* ------------------------------------------------------------ */ - /** - * Sets the log threshold. - * - * @param percent the new log threshold - */ - public void setLogThreshold(int percent) - { - _logThreshold = percent; - } - - /* ------------------------------------------------------------ */ - /** - * Gets the stack depth. - * - * @return the stack depth - */ - public int getStackDepth() - { - return _stackDepth; - } - - /* ------------------------------------------------------------ */ - /** - * Sets the stack depth. - * - * @param stackDepth the new stack depth - */ - public void setStackDepth(int stackDepth) - { - _stackDepth = stackDepth; - } - - /* ------------------------------------------------------------ */ - /** - * Sets the stack trace trail length. - * - * @param trailLength the new trail length - */ - public void setTrailLength(int trailLength) - { - _trailLength = trailLength; - } - - /* ------------------------------------------------------------ */ - /** - * Gets the stack trace trail length. - * - * @return the trail length - */ - public int getTrailLength() - { - return _trailLength; - } - - /* ------------------------------------------------------------ */ - /** - * Enable logging of CPU usage. - * - * @param frequencyMs the logging frequency - * @param thresholdPercent the logging threshold - */ - public void logCpuUsage(int frequencyMs, int thresholdPercent) - { - setLogInterval(frequencyMs); - setLogThreshold(thresholdPercent); - } - - /* ------------------------------------------------------------ */ - /** - * @return A {@link Dumpable} that is dumped whenever spinning threads are detected - */ - public Dumpable getDumpable() - { - return _dumpable; - } - - /* ------------------------------------------------------------ */ - /** - * @param dumpable A {@link Dumpable} that is dumped whenever spinning threads are detected - */ - public void setDumpable(Dumpable dumpable) - { - _dumpable = dumpable; - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart() - */ - public void doStart() - { - _done = false; - - _runner = new Thread(this); - _runner.setDaemon(true); - _runner.start(); - - LOG.info("Thread Monitor started successfully"); - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop() - */ - public void doStop() - { - if (_runner != null) - { - _done = true; - try - { - _runner.join(); - } - catch (InterruptedException ex) {} - - _monitorInfo.clear(); - } - } - - /* ------------------------------------------------------------ */ - /** - * Retrieve all avaliable thread ids - * - * @return array of thread ids - */ - protected long[] getAllThreadIds() - { - return _threadBean.getAllThreadIds(); - } - - /* ------------------------------------------------------------ */ - /** - * Retrieve the cpu time for specified thread. - * - * @param id thread id - * @return cpu time of the thread - */ - protected long getThreadCpuTime(long id) - { - return _threadBean.getThreadCpuTime(id); - } - - /* ------------------------------------------------------------ */ - /** - * Initialize JMX objects. - */ - protected void init() - { - _threadBean = ManagementFactory.getThreadMXBean(); - if (_threadBean.isThreadCpuTimeSupported()) - { - _threadBean.setThreadCpuTimeEnabled(true); - } - } - - /* ------------------------------------------------------------ */ - /** - * @see java.lang.Runnable#run() - */ - public void run() - { - // Initialize repeat flag - boolean repeat = false; - boolean scanNow, logNow; - - // Set next scan time and log time - long nextScanTime = System.currentTimeMillis(); - long nextLogTime = nextScanTime + _logInterval; - - while (!_done) - { - long currTime = System.currentTimeMillis(); - scanNow = (currTime > nextScanTime); - logNow = (_logInterval > 0 && currTime > nextLogTime); - if (repeat || scanNow || logNow) - { - repeat = collectThreadInfo(); - logThreadInfo(logNow); - - if (scanNow) - { - nextScanTime = System.currentTimeMillis() + _scanInterval; - } - if (logNow) - { - nextLogTime = System.currentTimeMillis() + _logInterval; - } - } - - // Sleep only if not going to repeat scanning immediately - if (!repeat) - { - try - { - Thread.sleep(100); - } - catch (InterruptedException ex) - { - LOG.ignore(ex); - } - } - } - - } - - /* ------------------------------------------------------------ */ - /** - * Collect thread info. - */ - private boolean collectThreadInfo() - { - boolean repeat = false; - try - { - // Retrieve stack traces for all threads at once as it - // was proven to be an order of magnitude faster when - // retrieving a single thread stack trace. - Map all = Thread.getAllStackTraces(); - - Set newOrUpdatedIds = new HashSet(); - - for (Map.Entry entry : all.entrySet()) - { - Thread thread = entry.getKey(); - long threadId = thread.getId(); - - // Skip our own runner thread - if (threadId == _runner.getId()) - { - continue; - } - - ThreadMonitorInfo currMonitorInfo = _monitorInfo.get(Long.valueOf(threadId)); - if (currMonitorInfo == null) - { - // Create thread info object for a new thread - currMonitorInfo = new ThreadMonitorInfo(thread); - currMonitorInfo.setStackTrace(entry.getValue()); - currMonitorInfo.setCpuTime(getThreadCpuTime(threadId)); - currMonitorInfo.setSampleTime(System.nanoTime()); - _monitorInfo.put(Long.valueOf(threadId), currMonitorInfo); - } - else - { - // Update the existing thread info object - currMonitorInfo.setStackTrace(entry.getValue()); - currMonitorInfo.setCpuTime(getThreadCpuTime(threadId)); - currMonitorInfo.setSampleTime(System.nanoTime()); - - // Stack trace count holds logging state - int count = currMonitorInfo.getTraceCount(); - if (count >= 0 && currMonitorInfo.isSpinning()) - { - // Thread was spinning and was logged before - if (count < _trailLength) - { - // Log another stack trace - currMonitorInfo.setTraceCount(count+1); - repeat = true; - continue; - } - - // Reset spin flag and trace count - currMonitorInfo.setSpinning(false); - currMonitorInfo.setTraceCount(-1); - } - if (currMonitorInfo.getCpuUtilization() > _busyThreshold) - { - // Thread is busy - StackTraceElement[] lastStackTrace = currMonitorInfo.getStackTrace(); - - if (lastStackTrace != null - && matchStackTraces(lastStackTrace, entry.getValue())) - { - // Thread is spinning - currMonitorInfo.setSpinning(true); - if (count < 0) - { - // Enable logging of spin status and stack traces - // only if the incoming trace count is negative - // that indicates a new scan for this thread - currMonitorInfo.setTraceCount(0); - repeat = (_trailLength > 0); - } - } - } - } - newOrUpdatedIds.add(Long.valueOf(threadId)); - } - - //clean out threads that no longer exist - Iterator iter = _monitorInfo.keySet().iterator(); - while (iter.hasNext()) - { - Long id = iter.next(); - if (!newOrUpdatedIds.contains(id)) - iter.remove(); - } - newOrUpdatedIds.clear(); - } - catch (Exception ex) - { - LOG.debug(ex); - } - return repeat; - } - - /* ------------------------------------------------------------ */ - protected void logThreadInfo(boolean logAll) - { - if (_monitorInfo.size() > 0) - { - // Select thread objects for all live threads - long[] running = getAllThreadIds(); - List all = new ArrayList(); - for (int idx=0; idx() - { - /* ------------------------------------------------------------ */ - public int compare(ThreadMonitorInfo info1, ThreadMonitorInfo info2) - { - return (int)Math.signum(info2.getCpuUtilization()-info1.getCpuUtilization()); - } - }); - - String format = "Thread '%2$s'[%3$s,id:%1$d,cpu:%4$.2f%%]%5$s"; - - // Log thread information for threads that exceed logging threshold - // or log spinning threads if their trace count is zero - boolean spinning=false; - for (ThreadMonitorInfo info : all) - { - if (logAll && info.getCpuUtilization() > _logThreshold - || info.isSpinning() && info.getTraceCount() == 0) - { - String message = String.format(format, - info.getThreadId(), info.getThreadName(), - info.getThreadState(), info.getCpuUtilization(), - info.isSpinning() ? " SPINNING" : ""); - _logger.info(message); - spinning=true; - } - } - - // Dump info - if (spinning && _dumpable!=null) - { - System.err.println(_dumpable.dump()); - } - - // Log stack traces for spinning threads with positive trace count - for (ThreadMonitorInfo info : all) - { - if (info.isSpinning() && info.getTraceCount() >= 0) - { - String message = String.format(format, - info.getThreadId(), info.getThreadName(), - info.getThreadState(), info.getCpuUtilization(), - " STACK TRACE"); - _logger.warn(new ThreadMonitorException(message, info.getStackTrace())); - } - } - } - } - - /* ------------------------------------------------------------ */ - /** - * Match stack traces. - * - * @param lastStackTrace last stack trace - * @param stackTrace current stack trace - * @return true, if successful - */ - private boolean matchStackTraces(StackTraceElement[] lastStackTrace, StackTraceElement[] stackTrace) - { - boolean match = true; - int count = Math.min(_stackDepth, Math.min(lastStackTrace.length, stackTrace.length)); - - for (int idx=0; idx < count; idx++) - { - if (!stackTrace[idx].equals(lastStackTrace[idx])) - { - match = false; - break; - } - } - return match; - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorAction.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorAction.java deleted file mode 100644 index 54267df40a4..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorAction.java +++ /dev/null @@ -1,409 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.integration; - -import static java.lang.Integer.parseInt; -import static java.lang.System.getProperty; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.Socket; -import java.net.URL; -import java.util.Collection; -import java.util.Map; -import java.util.Properties; -import java.util.Set; - -import javax.management.MBeanServerConnection; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.util.BytesContentProvider; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.monitor.JMXMonitor; -import org.eclipse.jetty.monitor.jmx.EventNotifier; -import org.eclipse.jetty.monitor.jmx.EventState; -import org.eclipse.jetty.monitor.jmx.EventState.TriggerState; -import org.eclipse.jetty.monitor.jmx.EventTrigger; -import org.eclipse.jetty.monitor.jmx.MonitorAction; -import org.eclipse.jetty.monitor.triggers.AggregateEventTrigger; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.thread.QueuedThreadPool; - -public class JavaMonitorAction extends MonitorAction -{ - private static final Logger LOG = Log.getLogger(JavaMonitorAction.class); - - private final HttpClient _client; - - private final String _url; - private final String _uuid; - private final String _appid; - - private String _srvip; - private String _session; - - /* ------------------------------------------------------------ */ - public JavaMonitorAction(EventNotifier notifier, String url, String uuid, String appid, long pollInterval) - throws Exception - { - super(new AggregateEventTrigger(),notifier,pollInterval); - - _url = url; - _uuid = uuid; - _appid = appid; - - QueuedThreadPool executor = new QueuedThreadPool(); - executor.setName(executor.getName() + "-monitor"); - _client = new HttpClient(); - _client.setExecutor(executor); - - try - { - _client.start(); - _srvip = getServerIP(); - } - catch (Exception ex) - { - LOG.debug(ex); - } - - sendData(new Properties()); - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.monitor.jmx.MonitorAction#execute(org.eclipse.jetty.monitor.jmx.EventTrigger, org.eclipse.jetty.monitor.jmx.EventState, long) - */ - @Override - public void execute(EventTrigger trigger, EventState state, long timestamp) - { - exec(trigger, state, timestamp); - } - - /* ------------------------------------------------------------ */ - /** - * @param trigger - * @param state - * @param timestamp - */ - private void exec(EventTrigger trigger, EventState state, long timestamp) - { - Collection> trs = state.values(); - - Properties data = new Properties(); - for (TriggerState ts : trs) - { - Object value = ts.getValue(); - - StringBuffer buffer = new StringBuffer(); - buffer.append(value == null ? "" : value.toString()); - buffer.append("|"); - buffer.append(getClassID(value)); - buffer.append("||"); - buffer.append(ts.getDescription()); - - data.setProperty(ts.getID(), buffer.toString()); - - try - { - sendData(data); - } - catch (Exception ex) - { - LOG.debug(ex); - } - } - } - - /* ------------------------------------------------------------ */ - /** - * @param data - * @throws Exception - */ - private void sendData(Properties data) - throws Exception - { - data.put("account", _uuid); - data.put("appserver", "Jetty"); - data.put("localIp", _srvip); - if (_appid == null) - data.put("lowestPort", getHttpPort()); - else - data.put("lowestPort", _appid); - if (_session != null) - data.put("session", _session); - - Properties response = sendRequest(data); - - parseResponse(response); - } - - /* ------------------------------------------------------------ */ - /** - * @param request - * @return - * @throws Exception - */ - private Properties sendRequest(Properties request) - throws Exception - { - ByteArrayOutputStream reqStream = null; - ByteArrayInputStream resStream = null; - Properties response = null; - - try { - reqStream = new ByteArrayOutputStream(); - request.storeToXML(reqStream,null); - - ContentResponse r3sponse = _client.POST(_url) - .header("Connection","close") - .content(new BytesContentProvider(reqStream.toByteArray())) - .send(); - - - if (r3sponse.getStatus() == HttpStatus.OK_200) - { - response = new Properties(); - resStream = new ByteArrayInputStream(r3sponse.getContent()); - response.loadFromXML(resStream); - } - } - finally - { - try - { - if (reqStream != null) - reqStream.close(); - } - catch (IOException ex) - { - LOG.ignore(ex); - } - - try - { - if (resStream != null) - resStream.close(); - } - catch (IOException ex) - { - LOG.ignore(ex); - } - } - - return response; - } - - /* ------------------------------------------------------------ */ - private void parseResponse(Properties response) - { - if (response.get("onhold") != null) - throw new Error("Suspended"); - - - if (response.get("session") != null) - { - _session = (String) response.remove("session"); - - AggregateEventTrigger trigger = (AggregateEventTrigger)getTrigger(); - - String queryString; - ObjectName[] queryResults; - for (Map.Entry entry : response.entrySet()) - { - String[] values = ((String) entry.getValue()).split("\\|"); - - queryString = values[0]; - if (queryString.startsWith("com.javamonitor.openfire")) - continue; - - if (queryString.startsWith("com.javamonitor")) - { - queryString = "org.eclipse.jetty.monitor.integration:type=javamonitortools,id=0"; - } - - queryResults = null; - try - { - queryResults = queryNames(queryString); - } - catch (IOException e) - { - LOG.debug(e); - } - catch (MalformedObjectNameException e) - { - LOG.debug(e); - } - - if (queryResults != null) - { - int idx = 0; - for(ObjectName objName : queryResults) - { - String id = entry.getKey().toString()+(idx == 0 ? "" : ":"+idx); - String name = queryString.equals(objName.toString()) ? "" : objName.toString(); - boolean repeat = Boolean.parseBoolean(values[2]); - trigger.add(new JavaMonitorTrigger(objName, values[1], id, name, repeat)); - } - } - } - } - } - - /* ------------------------------------------------------------ */ - /** - * @param value - * @return - */ - private int getClassID(final Object value) - { - if (value == null) - return 0; - - if (value instanceof Byte || - value instanceof Short || - value instanceof Integer || - value instanceof Long) - return 1; - - if (value instanceof Float || - value instanceof Double) - return 2; - - if (value instanceof Boolean) - return 3; - - return 4; // String - } - - /* ------------------------------------------------------------ */ - /** - * @return - * @throws Exception - */ - private String getServerIP() - throws Exception - { - Socket s = null; - try { - if (getProperty("http.proxyHost") != null) - { - s = new Socket(getProperty("http.proxyHost"), - parseInt(getProperty("http.proxyPort", "80"))); - } - else - { - int port = 80; - - URL url = new URL(_url); - if (url.getPort() != -1) { - port = url.getPort(); - } - s = new Socket(url.getHost(), port); - } - return s.getLocalAddress().getHostAddress(); - } - finally - { - try - { - if (s != null) - s.close(); - } - catch (IOException ex) - { - LOG.ignore(ex); - } - } - } - - /* ------------------------------------------------------------ */ - public Integer getHttpPort() - { - Collection connectors = null; - MBeanServerConnection service; - try - { - service = JMXMonitor.getServiceConnection(); - - connectors = service.queryNames(new ObjectName("org.eclipse.jetty.nio:type=selectchannelconnector,*"), null); - if (connectors != null && connectors.size() > 0) - { - Integer lowest = Integer.MAX_VALUE; - for (final ObjectName connector : connectors) { - lowest = (Integer)service.getAttribute(connector, "port"); - } - - if (lowest < Integer.MAX_VALUE) - return lowest; - } - } - catch (Exception ex) - { - LOG.debug(ex); - } - - return 0; - } - - /* ------------------------------------------------------------ */ - /** - * @param param - * @return - * @throws IOException - * @throws NullPointerException - * @throws MalformedObjectNameException - */ - private ObjectName[] queryNames(ObjectName param) - throws IOException, MalformedObjectNameException - { - ObjectName[] result = null; - - MBeanServerConnection connection = JMXMonitor.getServiceConnection(); - Set names = connection.queryNames(param, null); - if (names != null && names.size() > 0) - { - result = new ObjectName[names.size()]; - - int idx = 0; - for(Object name : names) - { - if (name instanceof ObjectName) - result[idx++] = (ObjectName)name; - else - result[idx++] = new ObjectName(name.toString()); - } - } - - return result; - } - - private ObjectName[] queryNames(String param) - throws IOException, MalformedObjectNameException - { - return queryNames(new ObjectName(param)); - } - - } diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorTools.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorTools.java deleted file mode 100644 index 090fb6d23a3..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorTools.java +++ /dev/null @@ -1,288 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.integration; - -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadInfo; -import java.lang.management.ThreadMXBean; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.security.Security; -import java.util.HashMap; -import java.util.Map; - -import org.eclipse.jetty.util.annotation.ManagedObject; -import org.eclipse.jetty.util.annotation.ManagedOperation; - -/** - * Derived from the JMX bean classes created by Kees Jan Koster for the java-monitor - * J2EE probe http://code.google.com/p/java-monitor-probes/source/browse/. - * - * @author Kees Jan Koster - */ -@ManagedObject("Java Monitoring Tools") -public class JavaMonitorTools -{ - private static final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); - - private static Method findDeadlockMethod = null; - - static - { - try - { - findDeadlockMethod = ThreadMXBean.class.getMethod("findDeadlockedThreads"); - } - catch (Exception ignored) - { - // this is a 1.5 JVM - try - { - findDeadlockMethod = ThreadMXBean.class.getMethod("findMonitorDeadlockedThreads"); - } - catch (SecurityException e) - { - e.printStackTrace(); - } - catch (NoSuchMethodException e) - { - e.printStackTrace(); - } - } - } - - private ThreadInfo[] findDeadlock() - throws IllegalAccessException, InvocationTargetException - { - final long[] threadIds = (long[])findDeadlockMethod.invoke(threadMXBean,(Object[])null); - - if (threadIds == null || threadIds.length < 1) - { - // no deadlock, we're done - return null; - } - - final ThreadInfo[] threads = threadMXBean.getThreadInfo(threadIds,Integer.MAX_VALUE); - return threads; - } - @ManagedOperation(value="Detailed report on the deadlocked threads.", impact="ACTION_INFO") - public String getDeadlockStacktraces() - { - try - { - final ThreadInfo[] threads = findDeadlock(); - if (threads == null) - { - // no deadlock, we're done - return null; - } - - return stacktraces(threads,0); - } - catch (Exception e) - { - return e.getMessage(); - } - } - - private static final int MAX_STACK = 10; - - private String stacktraces(final ThreadInfo[] threads, final int i) - { - if (i >= threads.length) - { - return ""; - } - final ThreadInfo thread = threads[i]; - - final StringBuilder trace = new StringBuilder(); - for (int stack_i = 0; stack_i < Math.min(thread.getStackTrace().length,MAX_STACK); stack_i++) - { - if (stack_i == (MAX_STACK - 1)) - { - trace.append(" ..."); - } - else - { - trace.append(" at ").append(thread.getStackTrace()[stack_i]).append("\n"); - } - } - - return "\"" + thread.getThreadName() + "\", id " + thread.getThreadId() + " is " + thread.getThreadState() + " on " + thread.getLockName() - + ", owned by " + thread.getLockOwnerName() + ", id " + thread.getLockOwnerId() + "\n" + trace + "\n\n" + stacktraces(threads,i + 1); - } - - /** - * We keep track of the last time we sampled the thread states. - * It is a crude optimization to avoid having to query for the - * threads states very often. - */ - private long lastSampled = 0L; - - private final Map states = new HashMap(); - - @ManagedOperation(value="Number of Blocked Threads") - public int getThreadsBlocked() - { - sampleThreads(); - - return states.get(Thread.State.BLOCKED); - } - - @ManagedOperation(value="Number of New Threads", impact="ACTION_INFO") - public int getThreadsNew() - { - sampleThreads(); - - return states.get(Thread.State.NEW); - } - - @ManagedOperation(value="Number of Terminated Threads", impact="ACTION_INFO") - public int getThreadsTerminated() - { - sampleThreads(); - - return states.get(Thread.State.TERMINATED); - } - - @ManagedOperation(value="Number of Sleeping and Waiting threads") - public int getThreadsTimedWaiting() - { - sampleThreads(); - - return states.get(Thread.State.TIMED_WAITING); - } - - @ManagedOperation(value="Number of Waiting Threads", impact="ACTION_INFO") - public int getThreadsWaiting() - { - sampleThreads(); - - return states.get(Thread.State.WAITING); - } - - @ManagedOperation(value="Number of Runnable Threads", impact="ACTION_INFO") - public int getThreadsRunnable() - { - sampleThreads(); - - return states.get(Thread.State.RUNNABLE); - } - - private synchronized void sampleThreads() - { - if ((lastSampled + 50L) < System.currentTimeMillis()) - { - lastSampled = System.currentTimeMillis(); - for (final Thread.State state : Thread.State.values()) - { - states.put(state,0); - } - - for (final ThreadInfo thread : threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds())) - { - if (thread != null) - { - final Thread.State state = thread.getThreadState(); - states.put(state,states.get(state) + 1); - } - else - { - states.put(Thread.State.TERMINATED,states.get(Thread.State.TERMINATED) + 1); - } - } - } - } - - private static final String POLICY = "sun.net.InetAddressCachePolicy"; - - @ManagedOperation(value="Amount of time successful DNS queries are cached for.") - public int getCacheSeconds() throws ClassNotFoundException, - IllegalAccessException, InvocationTargetException, - NoSuchMethodException { - final Class policy = Class.forName(POLICY); - final Object returnValue = policy.getMethod("get", (Class[]) null) - .invoke(null, (Object[]) null); - Integer seconds = (Integer) returnValue; - - return seconds.intValue(); - } - - @ManagedOperation(value="Amount of time failed DNS queries are cached for") - public int getCacheNegativeSeconds() throws ClassNotFoundException, - IllegalAccessException, InvocationTargetException, - NoSuchMethodException { - final Class policy = Class.forName(POLICY); - final Object returnValue = policy.getMethod("getNegative", - (Class[]) null).invoke(null, (Object[]) null); - Integer seconds = (Integer) returnValue; - - return seconds.intValue(); - } - - private static final String DEFAULT = "default"; - - private static final String SECURITY = "security"; - - private static final String SYSTEM = "system"; - - private static final String BOTH = "both"; - - private static final String SECURITY_TTL = "networkaddress.cache.ttl"; - - private static final String SYSTEM_TTL = "sun.net.inetaddr.ttl"; - - private static final String SECURITY_NEGATIVE_TTL = "networkaddress.cache.negative.ttl"; - - private static final String SYSTEM_NEGATIVE_TTL = "sun.net.inetaddr.negative.ttl"; - - @ManagedOperation(value="Cache policy for successful DNS lookups was changed from the hard-coded default") - public String getCacheTweakedFrom() { - if (Security.getProperty(SECURITY_TTL) != null) { - if (System.getProperty(SYSTEM_TTL) != null) { - return BOTH; - } - - return SECURITY; - } - - if (System.getProperty(SYSTEM_TTL) != null) { - return SYSTEM; - } - - return DEFAULT; - } - - @ManagedOperation(value="Cache policy for failed DNS lookups was changed from the hard-coded default") - public String getCacheNegativeTweakedFrom() { - if (Security.getProperty(SECURITY_NEGATIVE_TTL) != null) { - if (System.getProperty(SYSTEM_NEGATIVE_TTL) != null) { - return BOTH; - } - - return SECURITY; - } - - if (System.getProperty(SYSTEM_NEGATIVE_TTL) != null) { - return SYSTEM; - } - - return DEFAULT; - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorTrigger.java deleted file mode 100644 index 06a51d52641..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorTrigger.java +++ /dev/null @@ -1,74 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.integration; - -import javax.management.ObjectName; - -import org.eclipse.jetty.monitor.triggers.AttrEventTrigger; - - -/** - * @param the trigger type - */ -public class JavaMonitorTrigger > - extends AttrEventTrigger -{ - private final String _id; - private final String _name; - private final boolean _dynamic; - private int _count; - - /* ------------------------------------------------------------ */ - public JavaMonitorTrigger(ObjectName nameObject, String attributeName, String id, String name, boolean dynamic) - throws IllegalArgumentException - { - super(nameObject, attributeName); - - _id = id; - _name = name; - _dynamic = dynamic; - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.monitor.triggers.AttrEventTrigger#match(java.lang.Comparable) - */ - @Override - public boolean match(Comparable value) - { - return _dynamic ? true : (_count++ < 1); - } - - protected boolean getSaveAll() - { - return false; - } - - @Override - public String getID() - { - return _id; - } - - @Override - public String getNameString() - { - return _name; - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/ConsoleNotifier.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/ConsoleNotifier.java deleted file mode 100644 index bdfa6d1291d..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/ConsoleNotifier.java +++ /dev/null @@ -1,61 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.jmx; - - -/* ------------------------------------------------------------ */ -/** - * ConsoleNotifier - * - * Provides a way to output notification messages to the server console - */ -public class ConsoleNotifier implements EventNotifier -{ - String _messageFormat; - - - /* ------------------------------------------------------------ */ - /** - * Constructs a new notifier with specified format string - * - * @param format the {@link java.util.Formatter format string} - * @throws IllegalArgumentException if format is invalid - */ - public ConsoleNotifier(String format) - throws IllegalArgumentException - { - if (format == null) - throw new IllegalArgumentException("Message format cannot be null"); - - _messageFormat = format; - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.monitor.jmx.EventNotifier#notify(org.eclipse.jetty.monitor.jmx.EventTrigger, org.eclipse.jetty.monitor.jmx.EventState, long) - */ - public void notify(EventTrigger trigger, EventState state, long timestamp) - { - String output = String.format("%1$tF %1$tT.%1$tL:NOTIFY::", timestamp); - - output += String.format(_messageFormat, state); - - System.out.println(output); - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventNotifier.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventNotifier.java deleted file mode 100644 index 7f28c2b5b4f..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventNotifier.java +++ /dev/null @@ -1,40 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.jmx; - - -/* ------------------------------------------------------------ */ -/** - * EventNotifier - * - * Interface for classes used to send event notifications - */ -public interface EventNotifier -{ - - /* ------------------------------------------------------------ */ - /** - * This method is called when a notification event is received by the containing object - * - * @param trigger the event trigger - * @param state an {@link org.eclipse.jetty.monitor.jmx.EventState event state} - * @param timestamp time stamp of the event - */ - public void notify(EventTrigger trigger, EventState state, long timestamp); -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventState.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventState.java deleted file mode 100644 index abaecbc5c87..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventState.java +++ /dev/null @@ -1,209 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.jmx; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - - -/* ------------------------------------------------------------ */ -/** - * EventState - * - * Holds the state of one or more {@link org.eclipse.jetty.monitor.jmx.EventTrigger event trigger} - * instances to be used when sending notifications as well as executing the actions - * @param the event trigger type - */ -public class EventState -{ - - /* ------------------------------------------------------------ */ - /** - * State - * - * Holds the state of a single {@link org.eclipse.jetty.monitor.jmx.EventTrigger event trigger} - * @param the event trigger type - */ - public static class TriggerState - { - private final String _id; - private final String _desc; - private final TYPE _value; - - /* ------------------------------------------------------------ */ - /** - * Construct a trigger state - * - * @param id unique identification string of the associated event trigger - * @param desc description of the associated event trigger - * @param value effective value of the MXBean attribute (if applicable) - */ - public TriggerState(String id, String desc, TYPE value) - { - _id = id; - _desc = desc; - _value = value; - } - - /* ------------------------------------------------------------ */ - /** - * Retrieve the identification string of associated event trigger - * - * @return unique identification string - */ - public String getID() - { - return _id; - } - - /* ------------------------------------------------------------ */ - /** - * Retrieve the description string set by event trigger - * - * @return description string - */ - public String getDescription() - { - return _desc; - } - - /* ------------------------------------------------------------ */ - /** - * Retrieve the effective value of the MXBean attribute (if applicable) - * - * @return attribute value - */ - public TYPE getValue() - { - return _value; - } - - /* ------------------------------------------------------------ */ - /** - * @return string representation of the state - */ - public String toString() - { - StringBuilder result = new StringBuilder(); - - result.append(_desc); - result.append('='); - result.append(_value); - - return result.toString(); - } - } - - protected Map> _states; - - /* ------------------------------------------------------------ */ - /** - * Constructs an empty event state - */ - public EventState() - { - _states = new ConcurrentHashMap>(); - } - - - /* ------------------------------------------------------------ */ - /** - * Constructs an event state and adds a specified trigger state to it - * - * @param id unique identification string of the associated event trigger - * @param desc description of the associated event trigger - * @param value effective value of the MXBean attribute (if applicable) - */ - public EventState(String id, String desc, TYPE value) - { - this(); - - add(new TriggerState(id, desc, value)); - } - - /* ------------------------------------------------------------ */ - /** - * Adds a trigger state to the event state - * - * @param state trigger state to add - */ - public void add(TriggerState state) - { - _states.put(state.getID(), state); - } - - /* ------------------------------------------------------------ */ - /** - * Adds a collection of trigger states to the event state - * - * @param entries collection of trigger states to add - */ - public void addAll(Collection> entries) - { - for (TriggerState entry : entries) - { - add(entry); - } - } - - /* ------------------------------------------------------------ */ - /** - * Retrieves a single trigger state - * - * @param id unique identification string of the event trigger - * @return requested trigger state or null if not found - */ - public TriggerState get(String id) - { - return _states.get(id); - } - - /* ------------------------------------------------------------ */ - /** - * Retrieves a collection of all trigger states of the event state - * - * @return collection of the trigger states - */ - public Collection> values() - { - return Collections.unmodifiableCollection(_states.values()); - } - - /* ------------------------------------------------------------ */ - /** - * Returns a string representation of the event state - * - * @return string representation of the event state - */ - public String toString() - { - int cnt = 0; - StringBuilder result = new StringBuilder(); - - for (TriggerState value : _states.values()) - { - result.append(cnt++>0?"#":""); - result.append(value.toString()); - } - - return result.toString(); - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventTrigger.java deleted file mode 100644 index fcc7cfb3cab..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventTrigger.java +++ /dev/null @@ -1,76 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.monitor.jmx; - -import static java.util.UUID.randomUUID; - -/* ------------------------------------------------------------ */ -/** - * EventTrigger - * - * Abstract base class for all EventTrigger implementations. - * Used to determine whether the necessary conditions for - * triggering an event are present. - */ -public abstract class EventTrigger -{ - private final String _id; - - /* ------------------------------------------------------------ */ - /** - * Construct an event trigger - */ - public EventTrigger() - { - _id = randomUUID().toString(); - } - - /* ------------------------------------------------------------ */ - /** - * Retrieve the identification string of the event trigger - * - * @return unique identification string - */ - public String getID() - { - return _id; - } - - /* ------------------------------------------------------------ */ - /** - * Abstract method to verify if the event trigger conditions - * are in the appropriate state for an event to be triggered - * - * @param timestamp the timestamp to match - * @return true to trigger an event - * @throws Exception if unable to match - */ - public abstract boolean match(long timestamp) throws Exception; - - /* ------------------------------------------------------------ */ - /** - * Retrieve the event state associated with specified invocation - * of the event trigger match method - * - * @param timestamp time stamp associated with invocation - * @return event state or null if not found - */ - public abstract EventState getState(long timestamp); -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/LoggingNotifier.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/LoggingNotifier.java deleted file mode 100644 index 0c102e554d2..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/LoggingNotifier.java +++ /dev/null @@ -1,65 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.monitor.jmx; - -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - - -/* ------------------------------------------------------------ */ -/** - * ConsoleNotifier - * - * Provides a way to output notification messages to a log file - */ -public class LoggingNotifier implements EventNotifier -{ - private static final Logger LOG = Log.getLogger(LoggingNotifier.class); - - String _messageFormat; - - /* ------------------------------------------------------------ */ - /** - * Constructs a new notifier with specified format string - * - * @param format the {@link java.util.Formatter format string} - * @throws IllegalArgumentException if format is invalid - */ - public LoggingNotifier(String format) - throws IllegalArgumentException - { - if (format == null) - throw new IllegalArgumentException("Message format cannot be null"); - - _messageFormat = format; - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.monitor.jmx.EventNotifier#notify(org.eclipse.jetty.monitor.jmx.EventTrigger, org.eclipse.jetty.monitor.jmx.EventState, long) - */ - public void notify(EventTrigger trigger, EventState state, long timestamp) - { - String output = String.format(_messageFormat, state); - - LOG.info(output); - } - -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/MonitorAction.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/MonitorAction.java deleted file mode 100644 index 08017dde02a..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/MonitorAction.java +++ /dev/null @@ -1,179 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.jmx; - -import static java.util.UUID.randomUUID; - -import java.security.InvalidParameterException; - -/* ------------------------------------------------------------ */ -/** - * MonitorAction - * - * Abstract base class for all MonitorAction implementations. - * Receives notification when an associated EventTrigger is matched. - */ -public abstract class MonitorAction - extends NotifierGroup -{ - public static final int DEFAULT_POLL_INTERVAL = 5000; - - private final String _id; - private final EventTrigger _trigger; - private final EventNotifier _notifier; - private final long _pollInterval; - private final long _pollDelay; - - /* ------------------------------------------------------------ */ - /** - * Creates a new monitor action - * - * @param trigger event trigger to be associated with this action - * @throws InvalidParameterException if trigger is invalid - */ - public MonitorAction(EventTrigger trigger) - throws InvalidParameterException - { - this(trigger, null, 0, 0); - } - - - /* ------------------------------------------------------------ */ - /** - * Creates a new monitor action - * - * @param trigger event trigger to be associated with this action - * @param notifier event notifier to be associated with this action - * @throws InvalidParameterException if trigger is invalid - */ - public MonitorAction(EventTrigger trigger, EventNotifier notifier) - throws InvalidParameterException - { - this(trigger, notifier, 0); - } - - /* ------------------------------------------------------------ */ - /** - * Creates a new monitor action - * - * @param trigger event trigger to be associated with this action - * @param notifier event notifier to be associated with this action - * @param pollInterval interval for polling of the JMX server - * @throws InvalidParameterException if trigger is invalid - */ - public MonitorAction(EventTrigger trigger, EventNotifier notifier, long pollInterval) - throws InvalidParameterException - { - this(trigger, notifier, pollInterval, 0); - } - - /* ------------------------------------------------------------ */ - /** - * Creates a new monitor action - * - * @param trigger event trigger to be associated with this action - * @param notifier event notifier to be associated with this action - * @param pollInterval interval for polling of the JMX server - * @param pollDelay delay before starting to poll the JMX server - * @throws InvalidParameterException if trigger is invalid - */ - public MonitorAction(EventTrigger trigger, EventNotifier notifier, long pollInterval, long pollDelay) - throws InvalidParameterException - { - if (trigger == null) - throw new InvalidParameterException("Trigger cannot be null"); - - _id = randomUUID().toString(); - _trigger = trigger; - _notifier = notifier; - _pollInterval = pollInterval > 0 ? pollInterval : DEFAULT_POLL_INTERVAL; - _pollDelay = pollDelay > 0 ? pollDelay : _pollInterval; - } - - /* ------------------------------------------------------------ */ - /** - * Retrieve the identification string of the monitor action - * - * @return unique identification string - */ - - public final String getID() - { - return _id; - } - - - /* ------------------------------------------------------------ */ - /** - * Retrieve the event trigger of the monitor action - * - * @return associated event trigger - */ - public EventTrigger getTrigger() - { - return _trigger; - } - - /* ------------------------------------------------------------ */ - /** - * Retrieve the poll interval - * - * @return interval value (in milliseconds) - */ - public long getPollInterval() - { - return _pollInterval; - } - - - /* ------------------------------------------------------------ */ - /** Retrieve the poll delay - * @return delay value (in milliseconds) - */ - public long getPollDelay() - { - return _pollDelay; - } - - /* ------------------------------------------------------------ */ - /** - * This method will be called when event trigger associated - * with this monitor action matches its conditions. - * - * @param timestamp time stamp of the event - */ - public final void doExecute(long timestamp) - { - EventState state =_trigger.getState(timestamp); - if (_notifier != null) - _notifier.notify(_trigger, state, timestamp); - execute(_trigger, state, timestamp); - } - - /* ------------------------------------------------------------ */ - /** - * This method will be called to allow subclass to execute - * the desired action in response to the event. - * - * @param trigger event trigger associated with this monitor action - * @param state event state associated with current invocation of event trigger - * @param timestamp time stamp of the current invocation of event trigger - */ - public abstract void execute(EventTrigger trigger, EventState state, long timestamp); - } diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/MonitorTask.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/MonitorTask.java deleted file mode 100644 index 531fbf1d916..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/MonitorTask.java +++ /dev/null @@ -1,119 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.jmx; - -import java.util.HashMap; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.thread.ExecutorThreadPool; -import org.eclipse.jetty.util.thread.ThreadPool; - -/* ------------------------------------------------------------ */ -/** - * MonitorTask - * - * Invokes polling of the JMX server for the MBean attribute values - * through executing timer task scheduled using java.util.Timer - * at specified poll interval following a specified delay. - */ -public class MonitorTask extends TimerTask -{ - private static final Logger LOG = Log.getLogger(MonitorTask.class); - - private static Timer __timer = new Timer(true); - private static ThreadPool _callback = new ExecutorThreadPool(4,64,60,TimeUnit.SECONDS);; - private static Map __tasks = new HashMap(); - - private final MonitorAction _action; - - /* ------------------------------------------------------------ */ - /** - * Creates new instance of MonitorTask - * - * @param action instance of MonitorAction to use - */ - private MonitorTask(MonitorAction action) - { - _action = action; - } - - /* ------------------------------------------------------------ */ - /** - * Schedule new timer task for specified monitor action - * - * @param action monitor action - */ - public static void schedule(MonitorAction action) - { - TimerTask task = new MonitorTask(action); - __timer.scheduleAtFixedRate(task, - action.getPollDelay(), - action.getPollInterval()); - - __tasks.put(action.getID(), task); - } - - /* ------------------------------------------------------------ */ - /** - * Cancel timer task for specified monitor action - * - * @param action monitor action - */ - public static void cancel(MonitorAction action) - { - TimerTask task = __tasks.remove(action.getID()); - if (task != null) - task.cancel(); - } - - /* ------------------------------------------------------------ */ - /** - * This method is invoked when poll interval has elapsed - * to check if the event trigger conditions are satisfied - * in order to fire event. - * - * @see java.util.TimerTask#run() - */ - @Override - public final void run() - { - final long timestamp = System.currentTimeMillis(); - final EventTrigger trigger = _action.getTrigger(); - - _callback.execute(new Runnable() { - public void run() - { - try - { - if(trigger.match(timestamp)) - _action.doExecute(timestamp); - } - catch (Exception ex) - { - LOG.debug(ex); - } - } - }); - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/NotifierGroup.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/NotifierGroup.java deleted file mode 100644 index d67489bc16d..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/NotifierGroup.java +++ /dev/null @@ -1,119 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.jmx; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - - - -/* ------------------------------------------------------------ */ -/** - * NotifierGroup - * - * This class allows for grouping of the event notifiers - */ -public class NotifierGroup implements EventNotifier -{ - private Set _group; - - /* ------------------------------------------------------------ */ - /** - * Create a notifier group - */ - public NotifierGroup() - { - _group = new HashSet(); - } - - /* ------------------------------------------------------------ */ - /** - * Retrieve all event notifier associated with this group - * - * @return collection of event notifiers - */ - public Collection getNotifiers() - { - return Collections.unmodifiableSet(_group); - } - - /* ------------------------------------------------------------ */ - /** - * Add specified event notifier to event notifier group - * - * @param notifier event notifier to be added - * @return true if successful - */ - public boolean addNotifier(EventNotifier notifier) - { - return _group.add(notifier); - } - - /* ------------------------------------------------------------ */ - /** - * Add a collection of event notifiers to event notifier group - * - * @param notifiers collection of event notifiers to be added - * @return true if successful - */ - public boolean addNotifiers(Collection notifiers) - { - return _group.addAll(notifiers); - } - - /* ------------------------------------------------------------ */ - /** - * Remove event notifier from event notifier group - * - * @param notifier event notifier to be removed - * @return true if successful - */ - public boolean removeNotifier(EventNotifier notifier) - { - return _group.remove(notifier); - } - - /* ------------------------------------------------------------ */ - /** - * Remove a collection of event notifiers from event notifier group - * - * @param notifiers collection of event notifiers to be removed - * @return true if successful - */ - public boolean removeNotifiers(Collection notifiers) - { - return _group.removeAll(notifiers); - } - - /* ------------------------------------------------------------ */ - /** - * Invoke the notify() method of each of the notifiers in group - * - * @see org.eclipse.jetty.monitor.jmx.EventNotifier#notify(org.eclipse.jetty.monitor.jmx.EventTrigger, org.eclipse.jetty.monitor.jmx.EventState, long) - */ - public void notify(EventTrigger trigger, EventState state, long timestamp) - { - for (EventNotifier notifier: _group) - { - notifier.notify(trigger, state, timestamp); - } - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/ServiceConnection.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/ServiceConnection.java deleted file mode 100644 index 0088cccf05f..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/ServiceConnection.java +++ /dev/null @@ -1,172 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.jmx; - -import java.io.IOException; -import java.lang.management.ManagementFactory; - -import javax.management.MBeanServer; -import javax.management.MBeanServerConnection; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXConnectorServerFactory; -import javax.management.remote.JMXServiceURL; - -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - - -/* ------------------------------------------------------------ */ -/** - * ServerConnection - * - * Provides ability to create a connection to either an external - * JMX server, or a loopback connection to the internal one. - */ -public class ServiceConnection -{ - private static final Logger LOG = Log.getLogger(ServiceConnection.class); - - private String _serviceUrl; - private MBeanServer _server; - private JMXConnectorServer _connectorServer; - private JMXConnector _serverConnector; - private MBeanServerConnection _serviceConnection; - - /* ------------------------------------------------------------ */ - /** - * Construct a loopback connection to an internal server - * - * @throws IOException if unable to construct service connection - */ - public ServiceConnection() - throws IOException - { - this(null); - } - - /* ------------------------------------------------------------ */ - /** - * Construct a connection to specified server - * - * @param url URL of JMX server - * @throws IOException if unable to construct service connection - */ - public ServiceConnection(String url) - throws IOException - { - _serviceUrl = url; - } - - /** - * Retrieve an external URL for the JMX server - * - * @return service URL - */ - public String getServiceUrl() - { - return _serviceUrl; - } - - /* ------------------------------------------------------------ */ - /** - * Retrieve a connection to MBean server - * - * @return connection to MBean server - */ - public MBeanServerConnection getConnection() - { - return _serviceConnection; - } - - public void connect() - throws IOException - { - if (_serviceConnection == null) - { - if (_serviceUrl == null) - openLoopbackConnection(); - else - openServerConnection(_serviceUrl); - } - } - /* ------------------------------------------------------------ */ - /** - * Open a loopback connection to local JMX server - * - * @throws IOException - */ - private void openLoopbackConnection() - throws IOException - { - _server = ManagementFactory.getPlatformMBeanServer(); - - JMXServiceURL serviceUrl = new JMXServiceURL("service:jmx:rmi://"); - _connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(serviceUrl, null, _server); - _connectorServer.start(); - - _serviceUrl = _connectorServer.getAddress().toString(); - - _serverConnector = JMXConnectorFactory.connect(_connectorServer.getAddress()); - _serviceConnection = _serverConnector.getMBeanServerConnection(); - } - - /* ------------------------------------------------------------ */ - /** - * Open a connection to remote JMX server - * - * @param url - * @throws IOException - */ - private void openServerConnection(String url) - throws IOException - { - _serviceUrl = url; - - JMXServiceURL serviceUrl = new JMXServiceURL(_serviceUrl); - _serverConnector = JMXConnectorFactory.connect(serviceUrl); - _serviceConnection = _serverConnector.getMBeanServerConnection(); - } - - /* ------------------------------------------------------------ */ - /** - * Close the connections - */ - public void disconnect() - { - try - { - if (_serverConnector != null) - { - _serverConnector.close(); - _serviceConnection = null; - } - if (_connectorServer != null) - { - _connectorServer.stop(); - _connectorServer = null; - } - } - catch (Exception ex) - { - LOG.debug(ex); - } - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/SimpleAction.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/SimpleAction.java deleted file mode 100644 index a4feb7b0b74..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/SimpleAction.java +++ /dev/null @@ -1,46 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.jmx; - -import java.security.InvalidParameterException; - - - -/* ------------------------------------------------------------ */ -/** - */ -public class SimpleAction extends MonitorAction -{ - public SimpleAction(EventTrigger trigger, EventNotifier notifier, long pollInterval) - throws InvalidParameterException - { - super(trigger,notifier,pollInterval); - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.monitor.jmx.MonitorAction#execute(org.eclipse.jetty.monitor.jmx.EventTrigger, org.eclipse.jetty.monitor.jmx.EventState, long) - */ - - @Override - public void execute(EventTrigger trigger, EventState state, long timestamp) - { - System.out.printf("Action time: %tc%n", timestamp); - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/thread/ThreadMonitorInfo.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/thread/ThreadMonitorInfo.java deleted file mode 100644 index d8322d376f8..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/thread/ThreadMonitorInfo.java +++ /dev/null @@ -1,202 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.thread; - - -/* ------------------------------------------------------------ */ -/** - */ -public class ThreadMonitorInfo -{ - private Thread _thread; - private StackTraceElement[] _stackTrace; - - private boolean _threadSpinning = false; - private int _traceCount = -1; - - private long _prevCpuTime; - private long _prevSampleTime; - private long _currCpuTime; - private long _currSampleTime; - - - /* ------------------------------------------------------------ */ - /** - * Instantiates a new thread monitor info. - * - * @param thread the thread this object is created for - */ - public ThreadMonitorInfo(Thread thread) - { - _thread = thread; - } - - /* ------------------------------------------------------------ */ - /** - * @return Id of the thread - */ - public long getThreadId() - { - return _thread.getId(); - } - - /* ------------------------------------------------------------ */ - /** - * Gets the thread name. - * - * @return the thread name - */ - public String getThreadName() - { - return _thread.getName(); - } - - /* ------------------------------------------------------------ */ - /** - * Gets the thread state. - * - * @return the thread state - */ - public String getThreadState() - { - return _thread.getState().toString(); - } - - /* ------------------------------------------------------------ */ - /** - * Gets the stack trace. - * - * @return the stack trace - */ - public StackTraceElement[] getStackTrace() - { - return _stackTrace; - } - - /* ------------------------------------------------------------ */ - /** - * Sets the stack trace. - * - * @param stackTrace the new stack trace - */ - public void setStackTrace(StackTraceElement[] stackTrace) - { - _stackTrace = stackTrace; - } - - /* ------------------------------------------------------------ */ - /** - * Checks if is spinning. - * - * @return true, if is spinning - */ - public boolean isSpinning() - { - return _threadSpinning; - } - - /* ------------------------------------------------------------ */ - /** - * Sets the spinning flag. - * - * @param value the new value - */ - public void setSpinning(boolean value) - { - _threadSpinning = value; - } - - /* ------------------------------------------------------------ */ - /** - * Sets the trace count. - * - * @param traceCount the new trace count - */ - public void setTraceCount(int traceCount) - { - _traceCount = traceCount; - } - - /* ------------------------------------------------------------ */ - /** - * Gets the trace count. - * - * @return the trace count - */ - public int getTraceCount() - { - return _traceCount; - } - - /* ------------------------------------------------------------ */ - /** - * @return the CPU time of the thread - */ - public long getCpuTime() - { - return _currCpuTime; - } - - /* ------------------------------------------------------------ */ - /** - * Set the CPU time. - * - * @param ns new CPU time - */ - public void setCpuTime(long ns) - { - _prevCpuTime = _currCpuTime; - _currCpuTime = ns; - } - - /* ------------------------------------------------------------ */ - /** - * @return the time of sample - */ - public long getSampleTime() - { - return _currSampleTime; - } - - /* ------------------------------------------------------------ */ - /** - * Sets the sample time. - * - * @param ns the time of sample - */ - public void setSampleTime(long ns) - { - _prevSampleTime = _currSampleTime; - _currSampleTime = ns; - } - - /* ------------------------------------------------------------ */ - /** - * Gets the CPU utilization. - * - * @return the CPU utilization percentage - */ - public float getCpuUtilization() - { - long elapsedCpuTime = _currCpuTime - _prevCpuTime; - long elapsedNanoTime = _currSampleTime - _prevSampleTime; - - return elapsedNanoTime > 0 ? Math.min((elapsedCpuTime * 100.0f) / elapsedNanoTime, 100.0f) : 0; - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/thread/package-info.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/thread/package-info.java deleted file mode 100644 index 997ff01d1a3..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/thread/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -/** - * Jetty Monitor : Thread Monitoring - */ -package org.eclipse.jetty.monitor.thread; - diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AggregateEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AggregateEventTrigger.java deleted file mode 100644 index b8db4b92d85..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AggregateEventTrigger.java +++ /dev/null @@ -1,159 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.triggers; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.eclipse.jetty.monitor.jmx.EventState; -import org.eclipse.jetty.monitor.jmx.EventTrigger; - - -/* ------------------------------------------------------------ */ -/** - * AggregateEventTrigger - * - * EventTrigger aggregation that executes every aggregated event - * triggers in left to right order, and returns match if any one - * of them have returned match. - */ -public class AggregateEventTrigger extends EventTrigger -{ - protected final List _triggers; - - /* ------------------------------------------------------------ */ - /** - * Construct an event trigger - */ - public AggregateEventTrigger() - { - _triggers = new ArrayList(); - } - - /* ------------------------------------------------------------ */ - /** - * Construct an event trigger and associate the list - * of event triggers to be aggregated by this trigger - * - * @param triggers list of event triggers to add - */ - public AggregateEventTrigger(List triggers) - { - _triggers = new ArrayList(triggers); - } - - /* ------------------------------------------------------------ */ - /** - * Construct an event trigger and associate the array - * of event triggers to be aggregated by this trigger - * - * @param triggers list of event triggers to add - */ - public AggregateEventTrigger(EventTrigger... triggers) - { - _triggers = Arrays.asList(triggers); - } - - /* ------------------------------------------------------------ */ - public void add(EventTrigger trigger) - { - _triggers.add(trigger); - } - - /* ------------------------------------------------------------ */ - public void addAll(List triggers) - { - _triggers.addAll(triggers); - } - - /* ------------------------------------------------------------ */ - public void addAll(EventTrigger... triggers) - { - _triggers.addAll(Arrays.asList(triggers)); - } - - /* ------------------------------------------------------------ */ - /** - * Retrieve the event state associated with specified invocation - * of the event trigger match method. This event trigger retrieves - * the combined event state of all aggregated event triggers. - * - * @param timestamp time stamp associated with invocation - * @return event state or null if not found - * - * @see org.eclipse.jetty.monitor.jmx.EventTrigger#getState(long) - */ - @Override - public EventState getState(long timestamp) - { - EventState state = new EventState(); - - for (EventTrigger trigger : _triggers) - { - EventState subState = trigger.getState(timestamp); - if (subState != null) - { - state.addAll(subState.values()); - } - } - - return state; - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.monitor.jmx.EventTrigger#match(long) - */ - @Override - public boolean match(long timestamp) throws Exception - { - boolean result = false; - for(EventTrigger trigger : _triggers) - { - result = trigger.match(timestamp) ? true : result; - } - return true; - } - - /* ------------------------------------------------------------ */ - /** - * Returns the string representation of this event trigger - * in the format "AND(triger1,trigger2,...)". - * - * @return string representation of the event trigger - * - * @see java.lang.Object#toString() - */ - public String toString() - { - int cnt = 0; - StringBuilder result = new StringBuilder(); - - result.append("ANY("); - for (EventTrigger trigger : _triggers) - { - result.append(cnt++ > 0 ? "," : ""); - result.append(trigger); - } - result.append(')'); - - return result.toString(); - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AndEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AndEventTrigger.java deleted file mode 100644 index 5f2cf982a2d..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AndEventTrigger.java +++ /dev/null @@ -1,134 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.triggers; - -import java.util.Arrays; -import java.util.List; - -import org.eclipse.jetty.monitor.jmx.EventState; -import org.eclipse.jetty.monitor.jmx.EventTrigger; - - - -/* ------------------------------------------------------------ */ -/** - * AndEventTrigger - * - * EventTrigger aggregation using logical AND operation - * that executes matching of the aggregated event triggers - * in left to right order - */ -public class AndEventTrigger extends EventTrigger -{ - protected final List _triggers; - - /* ------------------------------------------------------------ */ - /** - * Construct an event trigger and associate the list - * of event triggers to be aggregated by this trigger - * - * @param triggers list of event triggers to add - */ - public AndEventTrigger(List triggers) - { - _triggers = triggers; - } - - /* ------------------------------------------------------------ */ - /** - * Construct an event trigger and associate the array - * of event triggers to be aggregated by this trigger - * - * @param triggers array of event triggers to add - */ - public AndEventTrigger(EventTrigger... triggers) - { - _triggers = Arrays.asList(triggers); - } - - /* ------------------------------------------------------------ */ - /** - * Verify if the event trigger conditions are in the - * appropriate state for an event to be triggered. - * This event trigger will match if all aggregated - * event triggers would return a match. - * - * @see org.eclipse.jetty.monitor.jmx.EventTrigger#match(long) - */ - public boolean match(long timestamp) - throws Exception - { - for(EventTrigger trigger : _triggers) - { - if (!trigger.match(timestamp)) - return false; - } - return true; - } - - /* ------------------------------------------------------------ */ - /** - * Retrieve the event state associated with specified invocation - * of the event trigger match method. This event trigger retrieves - * the combined event state of all aggregated event triggers. - * - * @param timestamp time stamp associated with invocation - * @return event state or null if not found - * - * @see org.eclipse.jetty.monitor.jmx.EventTrigger#getState(long) - */ - @Override - public EventState getState(long timestamp) - { - EventState state = new EventState(); - - for (EventTrigger trigger : _triggers) - { - EventState subState = trigger.getState(timestamp); - state.addAll(subState.values()); - } - - return state; - } - - /* ------------------------------------------------------------ */ - /** - * Returns the string representation of this event trigger - * in the format "AND(triger1,trigger2,...)". - * - * @return string representation of the event trigger - * - * @see java.lang.Object#toString() - */ - public String toString() - { - int cnt = 0; - StringBuilder result = new StringBuilder(); - - result.append("AND("); - for (EventTrigger trigger : _triggers) - { - result.append(cnt++ > 0 ? "," : ""); - result.append(trigger); - } - result.append(')'); - - return result.toString(); - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AttrEventTrigger.java deleted file mode 100644 index 02169a68b12..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AttrEventTrigger.java +++ /dev/null @@ -1,240 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.triggers; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import javax.management.MBeanServerConnection; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import javax.management.openmbean.CompositeData; - -import org.eclipse.jetty.monitor.JMXMonitor; -import org.eclipse.jetty.monitor.jmx.EventState; -import org.eclipse.jetty.monitor.jmx.EventTrigger; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -/** - * AttrEventTrigger - *

- * Event trigger that polls a value of an MXBean attribute - * and matches every invocation of this trigger. It can be - * used to send notifications of the value of an attribute - * of the MXBean being polled at a certain interval, or as - * a base class for the event triggers that match the - * value of an attribute of the MXBean being polled against - * some specified criteria. - * @param the event trigger type - */ -public class AttrEventTrigger> - extends EventTrigger -{ - private static final Logger LOG = Log.getLogger(AttrEventTrigger.class); - - private final ObjectName _nameObject; - - protected final String _objectName; - protected final String _attributeName; - protected Map> _states; - - /* ------------------------------------------------------------ */ - /** - * Construct event trigger and specify the MXBean attribute - * that will be polled by this event trigger. - * - * @param objectName object name of an MBean to be polled - * @param attributeName name of an MBean attribute to be polled - * - * @throws MalformedObjectNameException if unable to find object due to malformed name reference - * @throws IllegalArgumentException if parameters are invalid - */ - public AttrEventTrigger(String objectName, String attributeName) - throws MalformedObjectNameException, IllegalArgumentException - { - if (objectName == null) - throw new IllegalArgumentException("Object name cannot be null"); - if (attributeName == null) - throw new IllegalArgumentException("Attribute name cannot be null"); - - _states = new ConcurrentHashMap>(); - - _objectName = objectName; - _attributeName = attributeName; - - _nameObject = new ObjectName(_objectName); - } - - /* ------------------------------------------------------------ */ - /** - * Construct event trigger and specify the MXBean attribute - * that will be polled by this event trigger. - * - * @param nameObject object name of an MBean to be polled - * @param attributeName name of an MBean attribute to be polled - * - * @throws IllegalArgumentException if parameters are invalid - */ - public AttrEventTrigger(ObjectName nameObject, String attributeName) - throws IllegalArgumentException - { - if (nameObject == null) - throw new IllegalArgumentException("Object name cannot be null"); - if (attributeName == null) - throw new IllegalArgumentException("Attribute name cannot be null"); - - _states = new ConcurrentHashMap>(); - - _objectName = nameObject.toString(); - _attributeName = attributeName; - - _nameObject = nameObject; - } - - /* ------------------------------------------------------------ */ - /** - * Verify if the event trigger conditions are in the - * appropriate state for an event to be triggered. - * This event trigger uses the match(Comparable<TYPE>) - * method to compare the value of the MXBean attribute - * to the conditions specified by the subclasses. - * - * @see org.eclipse.jetty.monitor.jmx.EventTrigger#match(long) - */ - @SuppressWarnings("unchecked") - public final boolean match(long timestamp) - throws Exception - { - MBeanServerConnection serverConnection = JMXMonitor.getServiceConnection(); - - TYPE value = null; - try - { - int pos = _attributeName.indexOf('.'); - if (pos < 0) - value = (TYPE)serverConnection.getAttribute(_nameObject,_attributeName); - else - value = getValue((CompositeData)serverConnection.getAttribute(_nameObject, _attributeName.substring(0, pos)), - _attributeName.substring(pos+1)); - } - catch (Exception ex) - { - LOG.debug(ex); - } - - boolean result = false; - if (value != null) - { - result = match(value); - - if (result || getSaveAll()) - { - _states.put(timestamp, - new EventState(this.getID(), this.getNameString(), value)); - } - } - - return result; - } - - - /* ------------------------------------------------------------ */ - /** - * Verify if the event trigger conditions are in the - * appropriate state for an event to be triggered. - * Allows subclasses to override the default behavior - * that matches every invocation of this trigger - * @param value the value to match - * @return always true - */ - public boolean match(Comparable value) - { - return true; - } - - /* ------------------------------------------------------------ */ - /** - * Retrieve the event state associated with specified invocation - * of the event trigger match method. - * - * @param timestamp time stamp associated with invocation - * @return event state or null if not found - * - * @see org.eclipse.jetty.monitor.jmx.EventTrigger#getState(long) - */ - @Override - public final EventState getState(long timestamp) - { - return _states.get(timestamp); - } - - /* ------------------------------------------------------------ */ - /** - * Returns the string representation of this event trigger - * in the format "[object_name:attribute_name]". - * - * @return string representation of the event trigger - * - * @see java.lang.Object#toString() - */ - public String toString() - { - return getNameString(); - } - - /* ------------------------------------------------------------ */ - /** - * Returns the string representation of this event trigger - * in the format "[object_name:attribute_name]". Allows - * subclasses to override the name string used to identify - * this event trigger in the event state object as well as - * string representation of the subclasses. - * - * @return string representation of the event trigger - */ - protected String getNameString() - { - StringBuilder result = new StringBuilder(); - - result.append('['); - result.append(_objectName); - result.append(":"); - result.append(_attributeName); - result.append("]"); - - return result.toString(); - } - - protected boolean getSaveAll() - { - return true; - } - - protected TYPE getValue(CompositeData compValue, String fieldName) - { - int pos = fieldName.indexOf('.'); - if (pos < 0) - return (TYPE)compValue.get(fieldName); - else - return getValue((CompositeData)compValue.get(fieldName.substring(0, pos)), - fieldName.substring(pos+1)); - - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/EqualToAttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/EqualToAttrEventTrigger.java deleted file mode 100644 index 48aca3c5743..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/EqualToAttrEventTrigger.java +++ /dev/null @@ -1,89 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.triggers; - -import javax.management.MalformedObjectNameException; - - -/** - * EqualToAttrEventTrigger - *

- * Event trigger that polls a value of an MXBean attribute and - * checks if it is equal to specified value. - * @param the event trigger type - */ -public class EqualToAttrEventTrigger> extends AttrEventTrigger -{ - protected final TYPE _value; - - /* ------------------------------------------------------------ */ - /** - * Construct event trigger and specify the MXBean attribute - * that will be polled by this event trigger as well as the - * target value of the attribute. - * - * @param objectName object name of an MBean to be polled - * @param attributeName name of an MBean attribute to be polled - * @param value target value of the attribute - * - * @throws MalformedObjectNameException if unable to find object due to name issue - * @throws IllegalArgumentException on invalid parameters - */ - public EqualToAttrEventTrigger(String objectName, String attributeName, TYPE value) - throws MalformedObjectNameException, IllegalArgumentException - { - super(objectName,attributeName); - - if (value == null) - throw new IllegalArgumentException("Value cannot be null"); - - _value = value; - } - - /* ------------------------------------------------------------ */ - /** - * Compare the value of the MXBean attribute being polling - * to check if it is equal to the specified value. - */ - @Override - public boolean match(Comparable value) - { - return (value.compareTo(_value) == 0); - } - - /* ------------------------------------------------------------ */ - /** - * Returns the string representation of this event trigger - * in the format "name=value". - * - * @return string representation of the event trigger - * - * @see java.lang.Object#toString() - */ - public String toString() - { - StringBuilder result = new StringBuilder(); - - result.append(getNameString()); - result.append("=="); - result.append(_value); - - return result.toString(); - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/GreaterThanAttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/GreaterThanAttrEventTrigger.java deleted file mode 100644 index a091a660dfd..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/GreaterThanAttrEventTrigger.java +++ /dev/null @@ -1,90 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.triggers; - -import javax.management.MalformedObjectNameException; - -/** - * GreaterThanAttrEventTrigger - *

- * Event trigger that polls a value of an MXBean attribute and - * checks if it is greater than specified min value. - * @param event trigger type - */ -public class GreaterThanAttrEventTrigger> extends AttrEventTrigger -{ - protected final TYPE _min; - - /* ------------------------------------------------------------ */ - /** - * Construct event trigger and specify the MXBean attribute - * that will be polled by this event trigger as well as min - * value of the attribute. - * - * @param objectName object name of an MBean to be polled - * @param attributeName name of an MBean attribute to be polled - * @param min minimum value of the attribute - * - * @throws MalformedObjectNameException on bad object name - * @throws IllegalArgumentException on bad parameters - */ - public GreaterThanAttrEventTrigger(String objectName, String attributeName, TYPE min) - throws MalformedObjectNameException, IllegalArgumentException - { - super(objectName,attributeName); - - if (min == null) - throw new IllegalArgumentException("Value cannot be null"); - - _min = min; - } - - /* ------------------------------------------------------------ */ - /** - * Compare the value of the MXBean attribute being polling - * to check if it is greater than the min value. - * - * @see org.eclipse.jetty.monitor.triggers.AttrEventTrigger#match(java.lang.Comparable) - */ - @Override - public boolean match(Comparable value) - { - return (value.compareTo(_min) > 0); - } - - /* ------------------------------------------------------------ */ - /** - * Returns the string representation of this event trigger - * in the format "min<name". - * - * @return string representation of the event trigger - * - * @see java.lang.Object#toString() - */ - public String toString() - { - StringBuilder result = new StringBuilder(); - - result.append(_min); - result.append("<"); - result.append(getNameString()); - - return result.toString(); - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/GreaterThanOrEqualToAttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/GreaterThanOrEqualToAttrEventTrigger.java deleted file mode 100644 index c6383633d79..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/GreaterThanOrEqualToAttrEventTrigger.java +++ /dev/null @@ -1,90 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.triggers; - -import javax.management.MalformedObjectNameException; - -/** - * GreaterThanOrEqualToAttrEventTrigger - *

- * Event trigger that polls a value of an MXBean attribute and - * checks if it is greater than or equal to specified min value. - * @param event trigger type - */ -public class GreaterThanOrEqualToAttrEventTrigger> extends AttrEventTrigger -{ - protected final TYPE _min; - - /* ------------------------------------------------------------ */ - /** - * Construct event trigger and specify the MXBean attribute - * that will be polled by this event trigger as well as min - * value of the attribute. - * - * @param objectName object name of an MBean to be polled - * @param attributeName name of an MBean attribute to be polled - * @param min minimum value of the attribute - * - * @throws MalformedObjectNameException on bad object name - * @throws IllegalArgumentException on bad parameters - */ - public GreaterThanOrEqualToAttrEventTrigger(String objectName, String attributeName, TYPE min) - throws MalformedObjectNameException, IllegalArgumentException - { - super(objectName,attributeName); - - if (min == null) - throw new IllegalArgumentException("Value cannot be null"); - - _min = min; - } - - /* ------------------------------------------------------------ */ - /** - * Compare the value of the MXBean attribute being polling - * to check if it is greater than or equal to the min value. - * - * @see org.eclipse.jetty.monitor.triggers.AttrEventTrigger#match(java.lang.Comparable) - */ - @Override - public boolean match(Comparable value) - { - return (value.compareTo(_min) >= 0); - } - - /* ------------------------------------------------------------ */ - /** - * Returns the string representation of this event trigger - * in the format "min<=name". - * - * @return string representation of the event trigger - * - * @see java.lang.Object#toString() - */ - public String toString() - { - StringBuilder result = new StringBuilder(); - - result.append(_min); - result.append("<="); - result.append(getNameString()); - - return result.toString(); - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/LessThanAttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/LessThanAttrEventTrigger.java deleted file mode 100644 index 7457e628a75..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/LessThanAttrEventTrigger.java +++ /dev/null @@ -1,90 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.triggers; - -import javax.management.MalformedObjectNameException; - -/** - * LessThanAttrEventTrigger - *

- * Event trigger that polls a value of an MXBean attribute and - * checks if it is greater than specified max value. - * @param event trigger type - */ -public class LessThanAttrEventTrigger> extends AttrEventTrigger -{ - protected final TYPE _max; - - /* ------------------------------------------------------------ */ - /** - * Construct event trigger and specify the MXBean attribute - * that will be polled by this event trigger as well as max - * value of the attribute. - * - * @param objectName object name of an MBean to be polled - * @param attributeName name of an MBean attribute to be polled - * @param max maximum value of the attribute - * - * @throws MalformedObjectNameException on bad object name - * @throws IllegalArgumentException on bad parameters - */ - public LessThanAttrEventTrigger(String objectName, String attributeName, TYPE max) - throws MalformedObjectNameException, IllegalArgumentException - { - super(objectName,attributeName); - - if (max == null) - throw new IllegalArgumentException("Value cannot be null"); - - _max = max; - } - - /* ------------------------------------------------------------ */ - /** - * Compare the value of the MXBean attribute being polling - * to check if it is less than the min value. - * - * @see org.eclipse.jetty.monitor.triggers.AttrEventTrigger#match(java.lang.Comparable) - */ - @Override - public boolean match(Comparable value) - { - return (value.compareTo(_max) < 0); - } - - /* ------------------------------------------------------------ */ - /** - * Returns the string representation of this event trigger - * in the format "name<max". - * - * @return string representation of the event trigger - * - * @see java.lang.Object#toString() - */ - public String toString() - { - StringBuilder result = new StringBuilder(); - - result.append(getNameString()); - result.append("<"); - result.append(_max); - - return result.toString(); - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/LessThanOrEqualToAttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/LessThanOrEqualToAttrEventTrigger.java deleted file mode 100644 index de35ee34d79..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/LessThanOrEqualToAttrEventTrigger.java +++ /dev/null @@ -1,91 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.triggers; - -import javax.management.MalformedObjectNameException; - - -/** - * LessThanOrEqualToAttrEventTrigger - *

- * Event trigger that polls a value of an MXBean attribute and - * checks if it is less than or equal to specified max value. - * @param event trigger type - */ -public class LessThanOrEqualToAttrEventTrigger> extends AttrEventTrigger -{ - protected final TYPE _max; - - /* ------------------------------------------------------------ */ - /** - * Construct event trigger and specify the MXBean attribute - * that will be polled by this event trigger as well as max - * value of the attribute. - * - * @param objectName object name of an MBean to be polled - * @param attributeName name of an MBean attribute to be polled - * @param max maximum value of the attribute - * - * @throws MalformedObjectNameException on bad object name - * @throws IllegalArgumentException on bad parameters - */ - public LessThanOrEqualToAttrEventTrigger(String objectName, String attributeName, TYPE max) - throws MalformedObjectNameException, IllegalArgumentException - { - super(objectName,attributeName); - - if (max == null) - throw new IllegalArgumentException("Value cannot be null"); - - _max = max; - } - - /* ------------------------------------------------------------ */ - /** - * Compare the value of the MXBean attribute being polling - * to check if it is less than or equal to the max value. - * - * @see org.eclipse.jetty.monitor.triggers.AttrEventTrigger#match(java.lang.Comparable) - */ - @Override - public boolean match(Comparable value) - { - return (value.compareTo(_max) <= 0); - } - - /* ------------------------------------------------------------ */ - /** - * Returns the string representation of this event trigger - * in the format "name<=max". - * - * @return string representation of the event trigger - * - * @see java.lang.Object#toString() - */ - public String toString() - { - StringBuilder result = new StringBuilder(); - - result.append(getNameString()); - result.append("<="); - result.append(_max); - - return result.toString(); - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/OrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/OrEventTrigger.java deleted file mode 100644 index 31ac0496eb0..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/OrEventTrigger.java +++ /dev/null @@ -1,138 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.triggers; - -import java.util.Arrays; -import java.util.List; - -import org.eclipse.jetty.monitor.jmx.EventState; -import org.eclipse.jetty.monitor.jmx.EventTrigger; - - -/* ------------------------------------------------------------ */ -/** - * AndEventTrigger - * - * EventTrigger aggregation using logical OR operation - * that executes matching of the aggregated event triggers - * in left to right order - */ -public class OrEventTrigger - extends EventTrigger -{ - private final List _triggers; - - /* ------------------------------------------------------------ */ - /** - * Construct an event trigger and associate the list - * of event triggers to be aggregated by this trigger - * - * @param triggers list of event triggers to add - */ - public OrEventTrigger(List triggers) - { - _triggers = triggers; - } - - /* ------------------------------------------------------------ */ - /** - * Construct an event trigger and associate the array - * of event triggers to be aggregated by this trigger - * - * @param triggers array of event triggers to add - */ - public OrEventTrigger(EventTrigger... triggers) - { - _triggers = Arrays.asList(triggers); - } - - /* ------------------------------------------------------------ */ - /** - * Verify if the event trigger conditions are in the - * appropriate state for an event to be triggered. - * This event trigger will match if any of aggregated - * event triggers would return a match. - * - * @see org.eclipse.jetty.monitor.jmx.EventTrigger#match(long) - */ - public boolean match(long timestamp) - throws Exception - { - for(EventTrigger trigger : _triggers) - { - if (trigger.match(timestamp)) - return true; - } - return false; - } - - /* ------------------------------------------------------------ */ - /** - * Retrieve the event state associated with specified invocation - * of the event trigger match method. This event trigger retrieves - * the combined event state of all aggregated event triggers. - * - * @param timestamp time stamp associated with invocation - * @return event state or null if not found - * - * @see org.eclipse.jetty.monitor.jmx.EventTrigger#getState(long) - */ - @Override - @SuppressWarnings("unchecked") - public EventState getState(long timestamp) - { - EventState state = new EventState(); - - for (EventTrigger trigger : _triggers) - { - EventState subState = trigger.getState(timestamp); - if (subState!=null) - { - state.addAll(subState.values()); - } - } - - return state; - } - - /* ------------------------------------------------------------ */ - /** - * Returns the string representation of this event trigger - * in the format "OR(triger1,trigger2,...)". - * - * @return string representation of the event trigger - * - * @see java.lang.Object#toString() - */ - public String toString() - { - int cnt = 0; - StringBuilder result = new StringBuilder(); - - result.append("OR("); - for (EventTrigger trigger : _triggers) - { - result.append(cnt++ > 0 ? "," : ""); - result.append(trigger); - } - result.append(')'); - - return result.toString(); - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/RangeAttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/RangeAttrEventTrigger.java deleted file mode 100644 index bb3953befa1..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/RangeAttrEventTrigger.java +++ /dev/null @@ -1,99 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.triggers; - -import javax.management.MalformedObjectNameException; - -/** - * RangeAttrEventTrigger - *

- * Event trigger that polls a value of an MXBean attribute and - * checks if it is in a range from specified min value to - * specified max value. - * @param event trigger type - */ -public class RangeAttrEventTrigger> extends AttrEventTrigger -{ - protected final TYPE _min; - protected final TYPE _max; - - /* ------------------------------------------------------------ */ - /** - * Construct event trigger and specify the MXBean attribute - * that will be polled by this event trigger as well as min - * and max value of the attribute. - * - * @param objectName object name of an MBean to be polled - * @param attributeName name of an MBean attribute to be polled - * @param min minimum value of the attribute - * @param max maximum value of the attribute - * - * @throws MalformedObjectNameException on bad object name - * @throws IllegalArgumentException on bad parameters - */ - public RangeAttrEventTrigger(String objectName, String attributeName,TYPE min, TYPE max) - throws MalformedObjectNameException, IllegalArgumentException - { - super(objectName,attributeName); - - if (min == null) - throw new IllegalArgumentException("Value cannot be null"); - if (max == null) - throw new IllegalArgumentException("Value cannot be null"); - - _min = min; - _max = max; - } - - /* ------------------------------------------------------------ */ - /** - * Compare the value of the MXBean attribute being polling - * to check if it is in a range from specified min value to - * specified max value. - * - * @see org.eclipse.jetty.monitor.triggers.AttrEventTrigger#match(java.lang.Comparable) - */ - @Override - public boolean match(Comparable value) - { - return (value.compareTo(_min) > 0) &&(value.compareTo(_max) < 0); - } - - /* ------------------------------------------------------------ */ - /** - * Returns the string representation of this event trigger - * in the format "min<name<max". - * - * @return string representation of the event trigger - * - * @see java.lang.Object#toString() - */ - public String toString() - { - StringBuilder result = new StringBuilder(); - - result.append(_min); - result.append("<"); - result.append(getNameString()); - result.append("<"); - result.append(_max); - - return result.toString(); - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/RangeInclAttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/RangeInclAttrEventTrigger.java deleted file mode 100644 index 748fd7d4db0..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/RangeInclAttrEventTrigger.java +++ /dev/null @@ -1,99 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor.triggers; - -import javax.management.MalformedObjectNameException; - -/** - * RangeInclAttrEventTrigger - *

- * Event trigger that polls a value of an MXBean attribute and - * checks if it is in a range from specified min value to - * specified max value including the range bounds. - * @param event trigger type - */ -public class RangeInclAttrEventTrigger> extends AttrEventTrigger -{ - protected final TYPE _min; - protected final TYPE _max; - - /* ------------------------------------------------------------ */ - /** - * Construct event trigger and specify the MXBean attribute - * that will be polled by this event trigger as well as min - * and max value of the attribute. - * - * @param objectName object name of an MBean to be polled - * @param attributeName name of an MBean attribute to be polled - * @param min minimum value of the attribute - * @param max maximum value of the attribute - * - * @throws MalformedObjectNameException on bad object name - * @throws IllegalArgumentException on bad parameters - */ - public RangeInclAttrEventTrigger(String objectName, String attributeName,TYPE min, TYPE max) - throws MalformedObjectNameException, IllegalArgumentException - { - super(objectName,attributeName); - - if (min == null) - throw new IllegalArgumentException("Value cannot be null"); - if (max == null) - throw new IllegalArgumentException("Value cannot be null"); - - _min = min; - _max = max; - } - - /* ------------------------------------------------------------ */ - /** - * Compare the value of the MXBean attribute being polling - * to check if it is in a range from specified min value to - * specified max value including the range bounds. - * - * @see org.eclipse.jetty.monitor.triggers.AttrEventTrigger#match(java.lang.Comparable) - */ - @Override - public boolean match(Comparable value) - { - return (value.compareTo(_min) >= 0) &&(value.compareTo(_max) <= 0); - } - - /* ------------------------------------------------------------ */ - /** - * Returns the string representation of this event trigger - * in the format "min<=name<=max". - * - * @return string representation of the event trigger - * - * @see java.lang.Object#toString() - */ - public String toString() - { - StringBuilder result = new StringBuilder(); - - result.append(_min); - result.append("<="); - result.append(getNameString()); - result.append("<="); - result.append(_max); - - return result.toString(); - } -} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/package-info.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/package-info.java deleted file mode 100644 index 3f0ed871310..00000000000 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -/** - * Jetty Monitor : Triggers for Monitor Events - */ -package org.eclipse.jetty.monitor.triggers; - diff --git a/jetty-monitor/src/test/java/org/eclipse/jetty/monitor/AttrEventTriggerTest.java b/jetty-monitor/src/test/java/org/eclipse/jetty/monitor/AttrEventTriggerTest.java deleted file mode 100644 index bcb0fc2ea0c..00000000000 --- a/jetty-monitor/src/test/java/org/eclipse/jetty/monitor/AttrEventTriggerTest.java +++ /dev/null @@ -1,526 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor; - -import static org.junit.Assert.assertEquals; - -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.lang.management.ManagementFactory; -import java.util.Collection; -import java.util.Iterator; -import java.util.TreeSet; - -import javax.management.MBeanServer; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.jmx.MBeanContainer; -import org.eclipse.jetty.monitor.jmx.ConsoleNotifier; -import org.eclipse.jetty.monitor.jmx.EventNotifier; -import org.eclipse.jetty.monitor.jmx.EventState; -import org.eclipse.jetty.monitor.jmx.EventState.TriggerState; -import org.eclipse.jetty.monitor.jmx.EventTrigger; -import org.eclipse.jetty.monitor.jmx.MonitorAction; -import org.eclipse.jetty.monitor.triggers.AndEventTrigger; -import org.eclipse.jetty.monitor.triggers.AttrEventTrigger; -import org.eclipse.jetty.monitor.triggers.EqualToAttrEventTrigger; -import org.eclipse.jetty.monitor.triggers.GreaterThanAttrEventTrigger; -import org.eclipse.jetty.monitor.triggers.GreaterThanOrEqualToAttrEventTrigger; -import org.eclipse.jetty.monitor.triggers.LessThanAttrEventTrigger; -import org.eclipse.jetty.monitor.triggers.LessThanOrEqualToAttrEventTrigger; -import org.eclipse.jetty.monitor.triggers.OrEventTrigger; -import org.eclipse.jetty.monitor.triggers.RangeAttrEventTrigger; -import org.eclipse.jetty.monitor.triggers.RangeInclAttrEventTrigger; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - - -/* ------------------------------------------------------------ */ -/** - */ -public class AttrEventTriggerTest -{ - private static final Logger LOG = Log.getLogger(AttrEventTriggerTest.class); - - private Server _server; - private TestHandler _handler; - private RequestCounter _counter; - private JMXMonitor _monitor; - private HttpClient _client; - private String _requestUrl; - private MBeanContainer _mBeanContainer; - - @Before - public void setUp() - throws Exception - { - File docRoot = new File("target/test-output/docroot/"); - docRoot.mkdirs(); - docRoot.deleteOnExit(); - - System.setProperty("org.eclipse.jetty.util.log.DEBUG",""); - _server = new Server(); - - ServerConnector connector = new ServerConnector(_server); - connector.setPort(0); - _server.setConnectors(new Connector[] {connector}); - - _handler = new TestHandler(); - _server.setHandler(_handler); - - MBeanContainer.resetUnique(); - MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); - _mBeanContainer = new MBeanContainer(mBeanServer); - _server.addBean(_mBeanContainer,true); - _server.addBean(Log.getLog()); - - _counter = _handler.getRequestCounter(); - _server.addBean(_counter); - - _server.start(); - - startClient(); - - _monitor = new JMXMonitor(); - - int port = connector.getLocalPort(); - _requestUrl = "http://localhost:"+port+ "/"; - } - - @After - public void tearDown() - throws Exception - { - stopClient(); - - _mBeanContainer.destroy(); - - if (_server != null) - { - _server.stop(); - _server = null; - } - } - - @Test - public void testNoCondition() - throws Exception - { - long requestCount = 10; - - AttrEventTrigger trigger = - new AttrEventTrigger("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter"); - - EventNotifier notifier = new ConsoleNotifier("%s"); - CounterAction action = new CounterAction(trigger, notifier, 500, 100); - - performTest(action, requestCount, 1000); - - ResultSet result = new ResultSet(1,requestCount); - assertEquals(result, action.getHits()); - } - - @Test - public void testEqual_TRUE() - throws Exception - { - long requestCount = 10; - long testValue = 5; - - EqualToAttrEventTrigger trigger = - new EqualToAttrEventTrigger("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter",testValue); - - EventNotifier notifier = new ConsoleNotifier("%s"); - CounterAction action = new CounterAction(trigger, notifier, 500, 100); - - performTest(action, requestCount, 1000); - - ResultSet result = new ResultSet(testValue); - assertEquals(result, action.getHits()); - } - - @Test - public void testEqual_FALSE() - throws Exception - { - long requestCount = 10; - long testValue = 11; - - EqualToAttrEventTrigger trigger = - new EqualToAttrEventTrigger("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter", - testValue); - - EventNotifier notifier = new ConsoleNotifier("%s"); - CounterAction action = new CounterAction(trigger, notifier, 500, 100); - - performTest(action, requestCount, 1000); - - ResultSet result = new ResultSet(); - assertEquals(result, action.getHits()); - } - - @Test - public void testLowerLimit() - throws Exception - { - long requestCount = 10; - long testRangeLow = 5; - - GreaterThanAttrEventTrigger trigger = - new GreaterThanAttrEventTrigger("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter", - testRangeLow); - - EventNotifier notifier = new ConsoleNotifier("%s"); - CounterAction action = new CounterAction(trigger, notifier, 500, 100); - - performTest(action, requestCount, 1000); - - ResultSet result = new ResultSet(6,10); - assertEquals(result, action.getHits()); - } - - @Test - public void testLowerLimitIncl() - throws Exception - { - long requestCount = 10; - long testRangeLow = 5; - - GreaterThanOrEqualToAttrEventTrigger trigger = - new GreaterThanOrEqualToAttrEventTrigger("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter", - testRangeLow); - - EventNotifier notifier = new ConsoleNotifier("%s"); - CounterAction action = new CounterAction(trigger, notifier, 500, 100); - - performTest(action, requestCount, 1000); - - ResultSet result = new ResultSet(5,10); - assertEquals(result, action.getHits()); - } - - @Test - public void testUpperLimit() - throws Exception - { - long requestCount = 10; - long testRangeHigh = 5; - - LessThanAttrEventTrigger trigger = - new LessThanAttrEventTrigger("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter", - testRangeHigh); - - EventNotifier notifier = new ConsoleNotifier("%s"); - CounterAction action = new CounterAction(trigger, notifier, 500, 100); - - performTest(action, requestCount, 1000); - - ResultSet result = new ResultSet(1,4); - assertEquals(result, action.getHits()); - } - - - @Test - public void testUpperLimitIncl() - throws Exception - { - long requestCount = 10; - long testRangeHigh = 5; - - LessThanOrEqualToAttrEventTrigger trigger = - new LessThanOrEqualToAttrEventTrigger("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter", - testRangeHigh); - - EventNotifier notifier = new ConsoleNotifier("%s"); - CounterAction action = new CounterAction(trigger, notifier, 500, 100); - - performTest(action, requestCount, 1000); - - ResultSet result = new ResultSet(1,5); - assertEquals(result, action.getHits()); - } - - @Test - public void testRangeInclusive() - throws Exception - { - long requestCount = 10; - long testRangeLow = 3; - long testRangeHigh = 8; - - RangeInclAttrEventTrigger trigger = - new RangeInclAttrEventTrigger("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter", - testRangeLow, testRangeHigh); - - EventNotifier notifier = new ConsoleNotifier("%s"); - CounterAction action = new CounterAction(trigger, notifier, 500, 100); - - performTest(action, requestCount, 1000); - - ResultSet result = new ResultSet(testRangeLow,testRangeHigh); - assertEquals(result, action.getHits()); - } - - @Test - public void testInsideRangeExclusive() - throws Exception - { - long requestCount = 10; - long testRangeLow = 3; - long testRangeHigh = 8; - - RangeAttrEventTrigger trigger = - new RangeAttrEventTrigger("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter", - testRangeLow, testRangeHigh); - - EventNotifier notifier = new ConsoleNotifier("%s"); - CounterAction action = new CounterAction(trigger, notifier, 500, 100); - - performTest(action, requestCount, 1000); - - ResultSet result = new ResultSet(testRangeLow+1,testRangeHigh-1); - assertEquals(result, action.getHits()); - } - - @Test - public void testRangeComposite() - throws Exception - { - long requestCount = 10; - long testRangeLow = 4; - long testRangeHigh = 7; - - GreaterThanAttrEventTrigger trigger1 = - new GreaterThanAttrEventTrigger("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter", - testRangeLow); - LessThanOrEqualToAttrEventTrigger trigger2 = - new LessThanOrEqualToAttrEventTrigger("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter", - testRangeHigh); - AndEventTrigger trigger = new AndEventTrigger(trigger1, trigger2); - EventNotifier notifier = new ConsoleNotifier("%s"); - CounterAction action = new CounterAction(trigger, notifier, 500, 100); - - performTest(action, requestCount, 1000); - - ResultSet result = new ResultSet(testRangeLow+1,testRangeHigh); - assertEquals(result, action.getHits()); - } - - @Test - public void testRangeOuter() - throws Exception - { - long requestCount = 10; - long testRangeLow = 4; - long testRangeHigh = 7; - - LessThanOrEqualToAttrEventTrigger trigger1 = - new LessThanOrEqualToAttrEventTrigger("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter", - testRangeLow); - GreaterThanAttrEventTrigger trigger2 = - new GreaterThanAttrEventTrigger("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter", - testRangeHigh); - OrEventTrigger trigger = new OrEventTrigger(trigger1, trigger2); - EventNotifier notifier = new ConsoleNotifier("%s"); - CounterAction action = new CounterAction(trigger, notifier, 500, 100); - - performTest(action, requestCount, 1000); - - ResultSet result = new ResultSet(1,testRangeLow,testRangeHigh+1, requestCount); - assertEquals(result, action.getHits()); - } - - protected void performTest(MonitorAction action, long count, long interval) - throws Exception - { - _monitor.addActions(action); - - for (long cnt=0; cnt < count; cnt++) - { - try - { - //LOG.debug("Request: %s", _requestUrl); - ContentResponse r3sponse = _client.GET(_requestUrl); - - //ContentExchange getExchange = new ContentExchange(); - //getExchange.setURL(_requestUrl); - //getExchange.setMethod(HttpMethods.GET); - - //_client.send(getExchange); - //int state = getExchange.waitForDone(); - - String content = ""; - //int responseStatus = getExchange.getResponseStatus(); - if (r3sponse.getStatus() == HttpStatus.OK_200) - { - content = r3sponse.getContentAsString(); - } - else - { - LOG.info("response status", r3sponse.getStatus()); - } - - assertEquals(HttpStatus.OK_200,r3sponse.getStatus()); - Thread.sleep(interval); - } - catch (InterruptedException ex) - { - break; - } - } - - Thread.sleep(interval); - - _monitor.removeActions(action); - } - - protected void startClient()//Realm realm) - throws Exception - { - _client = new HttpClient(); - //_client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - //if (realm != null){ -// _client.setRealmResolver(new SimpleRealmResolver(realm)); - //} - _client.start(); - } - - protected void stopClient() - throws Exception - { - if (_client != null) - { - _client.stop(); - _client = null; - } - } - - protected static class TestHandler - extends AbstractHandler - { - private RequestCounter _counter = new RequestCounter(); - - public void handle(String target, Request baseRequest, - HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - if (baseRequest.isHandled()) { - return; - } - _counter.increment(); - - response.setContentType("text/plain"); - response.setStatus(HttpServletResponse.SC_OK); - PrintWriter writer = response.getWriter(); - writer.println("===TEST RESPONSE==="); - baseRequest.setHandled(true); - } - - public RequestCounter getRequestCounter() - { - return _counter; - } - } - - protected static class ResultSet extends TreeSet - { - public ResultSet() {} - - public ResultSet(long value) - { - add(value); - } - - public ResultSet(long start, long end) - { - addEntries(start, end); - } - - public ResultSet(long start, long pause, long resume, long end) - { - addEntries(start, pause); - addEntries(resume, end); - } - - public void addEntries(long start, long stop) - { - if (start > 0 && stop > 0) - { - for(long idx=start; idx <= stop; idx++) - { - add(idx); - } - } - } - - public boolean equals(ResultSet set) - { - return (this.size() == set.size()) && containsAll(set); - } - } - - protected static class CounterAction - extends MonitorAction - { - private ResultSet _hits = new ResultSet(); - - public CounterAction(EventTrigger trigger, EventNotifier notifier, long interval, long delay) - { - super(trigger, notifier, interval, delay); - } - - public void execute(EventTrigger trigger, EventState state, long timestamp) - { - if (trigger != null && state != null) - { - Collection values = state.values(); - - Iterator it = values.iterator(); - while(it.hasNext()) - { - TriggerState entry = (TriggerState)it.next(); - Object value = entry.getValue(); - if (value != null) - { - _hits.add((Long)value); - } - } - } - } - - public ResultSet getHits() - { - return _hits; - } - } -} diff --git a/jetty-monitor/src/test/java/org/eclipse/jetty/monitor/RequestCounter.java b/jetty-monitor/src/test/java/org/eclipse/jetty/monitor/RequestCounter.java deleted file mode 100644 index 934238f1604..00000000000 --- a/jetty-monitor/src/test/java/org/eclipse/jetty/monitor/RequestCounter.java +++ /dev/null @@ -1,48 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor; - -import org.eclipse.jetty.util.annotation.ManagedAttribute; -import org.eclipse.jetty.util.annotation.ManagedObject; -import org.eclipse.jetty.util.annotation.ManagedOperation; - - -@ManagedObject("TEST: Request Counter") -public class RequestCounter -{ - public long _counter; - - @ManagedAttribute("Get the value of the counter") - public synchronized long getCounter() - { - return _counter; - } - - @ManagedOperation("Increment the value of the counter") - public synchronized void increment() - { - _counter++; - } - - @ManagedOperation("Reset the counter") - public synchronized void reset() - { - _counter = 0; - } -} diff --git a/jetty-monitor/src/test/java/org/eclipse/jetty/monitor/ThreadMonitorTest.java b/jetty-monitor/src/test/java/org/eclipse/jetty/monitor/ThreadMonitorTest.java deleted file mode 100644 index 6072763179e..00000000000 --- a/jetty-monitor/src/test/java/org/eclipse/jetty/monitor/ThreadMonitorTest.java +++ /dev/null @@ -1,165 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.monitor; - -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.util.Random; -import java.util.concurrent.atomic.AtomicInteger; - -import org.eclipse.jetty.util.component.Dumpable; -import org.eclipse.jetty.util.log.StacklessLogging; -import org.junit.Ignore; -import org.junit.Test; - - -/* ------------------------------------------------------------ */ -/** - */ -public class ThreadMonitorTest -{ - public final static int DURATION=4000; - - @Ignore - @Test - public void monitorTest() throws Exception - { - try(StacklessLogging stackless=new StacklessLogging(ThreadMonitor.class)) - { - - final AtomicInteger countLogs=new AtomicInteger(0); - final AtomicInteger countSpin=new AtomicInteger(0); - - ThreadMonitor monitor = new ThreadMonitor(1000,50,1,1) - { - @Override - protected void logThreadInfo(boolean logAll) - { - if (logAll) - countLogs.incrementAndGet(); - else - countSpin.incrementAndGet(); - super.logThreadInfo(logAll); - } - }; - monitor.setDumpable(new Dumpable() - { - public void dump(Appendable out, String indent) throws IOException - { - out.append(dump()); - } - - public String dump() - { - return "Dump Spinning"; - } - }); - - monitor.logCpuUsage(2000,0); - monitor.start(); - - Random rnd = new Random(); - for (long cnt=0; cnt<100; cnt++) - { - long value = rnd.nextLong() % 50 + 50; - Sleeper sleeper = new Sleeper(value); - Thread runner = new Thread(sleeper); - runner.setDaemon(true); - runner.start(); - } - - Spinner spinner = new Spinner(); - Thread runner = new Thread(spinner); - runner.start(); - - Thread.sleep(DURATION); - - spinner.setDone(); - monitor.stop(); - - assertTrue(countLogs.get() >= 1); - assertTrue(countSpin.get() >= 2); - } - } - - - private class Spinner implements Runnable - { - private volatile boolean done = false; - - /* ------------------------------------------------------------ */ - public void setDone() - { - done = true; - } - - /* ------------------------------------------------------------ */ - public void run() - { - spin(); - } - - /* ------------------------------------------------------------ */ - public void spin() - { - long result=-1; - long end=TimeUnit.NANOSECONDS.toMillis(System.nanoTime())+DURATION+1000; - while (!done && TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) 1 ? fn(value-1) : 1; - - Thread.sleep(50); - - return result; - } - } -} diff --git a/jetty-monitor/src/test/resources/jetty-logging.properties b/jetty-monitor/src/test/resources/jetty-logging.properties deleted file mode 100644 index 2071498c3d6..00000000000 --- a/jetty-monitor/src/test/resources/jetty-logging.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -#org.eclipse.jetty.LEVEL=DEBUG -#org.eclipse.jetty.monitor.LEVEL=DEBUG diff --git a/jetty-nosql/src/main/config/modules/session-store-mongo.mod b/jetty-nosql/src/main/config/modules/session-store-mongo.mod index a0df7bafdcb..e3ffafdd42d 100644 --- a/jetty-nosql/src/main/config/modules/session-store-mongo.mod +++ b/jetty-nosql/src/main/config/modules/session-store-mongo.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables NoSql session management with a MongoDB driver. diff --git a/jetty-nosql/src/main/config/modules/sessions/mongo/address.mod b/jetty-nosql/src/main/config/modules/sessions/mongo/address.mod index 15fcfeae6d2..333877d8cb4 100644 --- a/jetty-nosql/src/main/config/modules/sessions/mongo/address.mod +++ b/jetty-nosql/src/main/config/modules/sessions/mongo/address.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Server/port address connections for session storage diff --git a/jetty-nosql/src/main/config/modules/sessions/mongo/uri.mod b/jetty-nosql/src/main/config/modules/sessions/mongo/uri.mod index fc43772b0b3..813904e4f8f 100644 --- a/jetty-nosql/src/main/config/modules/sessions/mongo/uri.mod +++ b/jetty-nosql/src/main/config/modules/sessions/mongo/uri.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] MongoURI connections for session storage diff --git a/jetty-osgi/test-jetty-osgi/pom.xml b/jetty-osgi/test-jetty-osgi/pom.xml index 9d20b12eabe..626e439f584 100644 --- a/jetty-osgi/test-jetty-osgi/pom.xml +++ b/jetty-osgi/test-jetty-osgi/pom.xml @@ -17,6 +17,7 @@ 4.11.0 2.5.2 1.0 + true @@ -424,32 +425,29 @@ - - - maven-surefire-plugin - 2.20.1 - - true - - ${settings.localRepository} - - - - - org.apache.servicemix.tooling - depends-maven-plugin - - - generate-depends-file - - generate-depends-file - - - - - + + maven-surefire-plugin + + ${skipTests} + + ${settings.localRepository} + + + + + org.apache.servicemix.tooling + depends-maven-plugin + + + generate-depends-file + + generate-depends-file + + + + org.eclipse.m2e @@ -477,6 +475,20 @@ + + + org.apache.servicemix.tooling + depends-maven-plugin + + + generate-depends-file + + generate-depends-file + + + + + @@ -516,20 +528,23 @@ test + + false + - - maven-surefire-plugin - - false - - **/TestJettyOSGiBootHTTP2JDK9* - - - - -Dmortbay-alpn-boot=${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/${alpn.version}/alpn-boot-${alpn.version}.jar - - + + maven-surefire-plugin + + + + **/TestJettyOSGiBootHTTP2JDK9* + + + + -Dmortbay-alpn-boot=${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/${alpn.version}/alpn-boot-${alpn.version}.jar + + @@ -570,12 +585,15 @@ test + + false + maven-surefire-plugin - false + ${skipTests} **/TestJettyOSGiBootHTTP2 diff --git a/jetty-overlay-deployer/src/main/config/modules/overlay.mod b/jetty-overlay-deployer/src/main/config/modules/overlay.mod index 1c95193c1de..8522e997103 100644 --- a/jetty-overlay-deployer/src/main/config/modules/overlay.mod +++ b/jetty-overlay-deployer/src/main/config/modules/overlay.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enable the jetty overlay deployer that allows webapplications to be dynamically composed of layers. diff --git a/jetty-proxy/src/main/config/modules/proxy.mod b/jetty-proxy/src/main/config/modules/proxy.mod index c14ee0cba76..b1be24399cf 100644 --- a/jetty-proxy/src/main/config/modules/proxy.mod +++ b/jetty-proxy/src/main/config/modules/proxy.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enable the Jetty Proxy, that allows the server to act as a non-transparent proxy for browsers. diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java index 4352745cd60..66b56dab016 100644 --- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java +++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java @@ -50,6 +50,7 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.util.HttpCookieStore; +import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.QueuedThreadPool; @@ -352,7 +353,7 @@ public abstract class AbstractProxyServlet extends HttpServlet */ protected HttpClient newHttpClient() { - int selectors = Math.max(1, Runtime.getRuntime().availableProcessors() / 2); + int selectors = Math.max(1,ProcessorUtils.availableProcessors()/2); String value = getServletConfig().getInitParameter("selectors"); if (value != null) selectors = Integer.parseInt(value); diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletLoadTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletLoadTest.java index 04f0446a902..9e7256904d1 100644 --- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletLoadTest.java +++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletLoadTest.java @@ -42,6 +42,7 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.QueuedThreadPool; @@ -149,7 +150,7 @@ public class ProxyServletLoadTest startClient(); // Number of clients to simulate - int clientCount = Runtime.getRuntime().availableProcessors(); + int clientCount = ProcessorUtils.availableProcessors(); // Latch for number of clients still active (used to terminate test) final CountDownLatch activeClientLatch = new CountDownLatch(clientCount); diff --git a/jetty-quickstart/src/main/config/modules/quickstart.mod b/jetty-quickstart/src/main/config/modules/quickstart.mod index cefa5f16887..102801714b6 100644 --- a/jetty-quickstart/src/main/config/modules/quickstart.mod +++ b/jetty-quickstart/src/main/config/modules/quickstart.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables the Jetty Quickstart module for rapid deployment of preconfigured webapplications. diff --git a/jetty-rewrite/src/main/config/modules/rewrite-compactpath.mod b/jetty-rewrite/src/main/config/modules/rewrite-compactpath.mod index f51f05d30af..bdd63f1f4e6 100644 --- a/jetty-rewrite/src/main/config/modules/rewrite-compactpath.mod +++ b/jetty-rewrite/src/main/config/modules/rewrite-compactpath.mod @@ -1,6 +1,5 @@ -# -# Jetty Rewrite CompactPath module -# +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Add a rule to the rewrite module to compact paths so that double slashes in the path are treated as a single slash. diff --git a/jetty-rewrite/src/main/config/modules/rewrite-customizer.mod b/jetty-rewrite/src/main/config/modules/rewrite-customizer.mod index 2546654f000..5caea6942c8 100644 --- a/jetty-rewrite/src/main/config/modules/rewrite-customizer.mod +++ b/jetty-rewrite/src/main/config/modules/rewrite-customizer.mod @@ -1,6 +1,5 @@ -# -# Jetty Rewrite Customizer module -# +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables a rewrite Rules container as a request customizer on the servers default HttpConfiguration instance diff --git a/jetty-rewrite/src/main/config/modules/rewrite.mod b/jetty-rewrite/src/main/config/modules/rewrite.mod index 3d61531dba2..60c229dfae9 100644 --- a/jetty-rewrite/src/main/config/modules/rewrite.mod +++ b/jetty-rewrite/src/main/config/modules/rewrite.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables the jetty-rewrite handler. Specific rewrite rules must be added to either to etc/jetty-rewrite.xml or a custom xml/module diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ValidUrlRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ValidUrlRule.java index b4c9f92e68e..67078aa83a3 100644 --- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ValidUrlRule.java +++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ValidUrlRule.java @@ -115,7 +115,7 @@ public class ValidUrlRule extends Rule LOG.debug("{} {} {} {}", Character.charCount(codepoint), codepoint, block, Character.isISOControl(codepoint)); - return (!Character.isISOControl(codepoint)) && block != null && block != Character.UnicodeBlock.SPECIALS; + return (!Character.isISOControl(codepoint)) && block != null && !Character.UnicodeBlock.SPECIALS.equals(block); } @Override diff --git a/jetty-security/src/main/config/modules/security.mod b/jetty-security/src/main/config/modules/security.mod index 3955fcfee84..ea56fdd6b6d 100644 --- a/jetty-security/src/main/config/modules/security.mod +++ b/jetty-security/src/main/config/modules/security.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Adds servlet standard security handling to the classpath. diff --git a/jetty-server/src/main/config/modules/connectionlimit.mod b/jetty-server/src/main/config/modules/connectionlimit.mod index b51829bfee7..997f38905a9 100644 --- a/jetty-server/src/main/config/modules/connectionlimit.mod +++ b/jetty-server/src/main/config/modules/connectionlimit.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enable a server wide connection limit diff --git a/jetty-server/src/main/config/modules/debug.mod b/jetty-server/src/main/config/modules/debug.mod index 9462422ff3c..b0cac1f827b 100644 --- a/jetty-server/src/main/config/modules/debug.mod +++ b/jetty-server/src/main/config/modules/debug.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables the DebugListener to generate additional logging regarding detailed request handling events. diff --git a/jetty-server/src/main/config/modules/debuglog.mod b/jetty-server/src/main/config/modules/debuglog.mod index 28e6d8c725d..860733475ef 100644 --- a/jetty-server/src/main/config/modules/debuglog.mod +++ b/jetty-server/src/main/config/modules/debuglog.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Deprecated Debug Log using the DebugHandle. Replaced with the debug module. diff --git a/jetty-server/src/main/config/modules/ext.mod b/jetty-server/src/main/config/modules/ext.mod index 3834181a301..103336000c6 100644 --- a/jetty-server/src/main/config/modules/ext.mod +++ b/jetty-server/src/main/config/modules/ext.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Adds all jar files discovered in $JETTY_HOME/lib/ext and $JETTY_BASE/lib/ext to the servers classpath. diff --git a/jetty-server/src/main/config/modules/gzip.mod b/jetty-server/src/main/config/modules/gzip.mod index b210a8c0fa8..63a8b99e9ba 100644 --- a/jetty-server/src/main/config/modules/gzip.mod +++ b/jetty-server/src/main/config/modules/gzip.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enable GzipHandler for dynamic gzip compression for the entire server. diff --git a/jetty-server/src/main/config/modules/home-base-warning.mod b/jetty-server/src/main/config/modules/home-base-warning.mod index 3e599f0788f..ee342355272 100644 --- a/jetty-server/src/main/config/modules/home-base-warning.mod +++ b/jetty-server/src/main/config/modules/home-base-warning.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Generates a warning that server has been run from $JETTY_HOME rather than from a $JETTY_BASE. diff --git a/jetty-server/src/main/config/modules/http-forwarded.mod b/jetty-server/src/main/config/modules/http-forwarded.mod index b84ca7ce3b1..34e25642b2c 100644 --- a/jetty-server/src/main/config/modules/http-forwarded.mod +++ b/jetty-server/src/main/config/modules/http-forwarded.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Adds a forwarded request customizer to the HTTP Connector to process forwarded-for style headers from a proxy. diff --git a/jetty-server/src/main/config/modules/http.mod b/jetty-server/src/main/config/modules/http.mod index c288d6ab5d9..aca43d87d9d 100644 --- a/jetty-server/src/main/config/modules/http.mod +++ b/jetty-server/src/main/config/modules/http.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables a HTTP connector on the server. By default HTTP/1 is support, but HTTP2C can diff --git a/jetty-server/src/main/config/modules/https.mod b/jetty-server/src/main/config/modules/https.mod index ad13224e2f8..8136579de2c 100644 --- a/jetty-server/src/main/config/modules/https.mod +++ b/jetty-server/src/main/config/modules/https.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Adds HTTPS protocol support to the TLS(SSL) Connector diff --git a/jetty-server/src/main/config/modules/jvm.mod b/jetty-server/src/main/config/modules/jvm.mod index 30b0d966b96..e8262f99028 100644 --- a/jetty-server/src/main/config/modules/jvm.mod +++ b/jetty-server/src/main/config/modules/jvm.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] A noop module that creates an ini template useful for setting JVM arguments (eg -Xmx ) diff --git a/jetty-server/src/main/config/modules/logback-access.mod b/jetty-server/src/main/config/modules/logback-access.mod index 9d5da6e144a..ee5ec462218 100644 --- a/jetty-server/src/main/config/modules/logback-access.mod +++ b/jetty-server/src/main/config/modules/logback-access.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables logback request log. diff --git a/jetty-server/src/main/config/modules/lowresources.mod b/jetty-server/src/main/config/modules/lowresources.mod index c68db526cbe..b1e91d7f7aa 100644 --- a/jetty-server/src/main/config/modules/lowresources.mod +++ b/jetty-server/src/main/config/modules/lowresources.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables a low resource monitor on the server that can take actions if threads and/or connections diff --git a/jetty-server/src/main/config/modules/proxy-protocol-ssl.mod b/jetty-server/src/main/config/modules/proxy-protocol-ssl.mod index a33efe84a99..7fb3d53e694 100644 --- a/jetty-server/src/main/config/modules/proxy-protocol-ssl.mod +++ b/jetty-server/src/main/config/modules/proxy-protocol-ssl.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables the Proxy Protocol on the TLS(SSL) Connector. http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt diff --git a/jetty-server/src/main/config/modules/proxy-protocol.mod b/jetty-server/src/main/config/modules/proxy-protocol.mod index 48820e5c145..38bcd8f96c0 100644 --- a/jetty-server/src/main/config/modules/proxy-protocol.mod +++ b/jetty-server/src/main/config/modules/proxy-protocol.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables the Proxy Protocol on the HTTP Connector. http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt diff --git a/jetty-server/src/main/config/modules/requestlog.mod b/jetty-server/src/main/config/modules/requestlog.mod index ef8630eb477..e8e971be87b 100644 --- a/jetty-server/src/main/config/modules/requestlog.mod +++ b/jetty-server/src/main/config/modules/requestlog.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables a NCSA style request log. diff --git a/jetty-server/src/main/config/modules/resources.mod b/jetty-server/src/main/config/modules/resources.mod index 00a5de93ba1..aebfebeeb70 100644 --- a/jetty-server/src/main/config/modules/resources.mod +++ b/jetty-server/src/main/config/modules/resources.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Adds the $JETTY_HOME/resources and/or $JETTY_BASE/resources directory to the server classpath. Useful for configuration diff --git a/jetty-server/src/main/config/modules/server.mod b/jetty-server/src/main/config/modules/server.mod index 9461a63bb9e..b0d1f3db12d 100644 --- a/jetty-server/src/main/config/modules/server.mod +++ b/jetty-server/src/main/config/modules/server.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables the core Jetty server on the classpath. diff --git a/jetty-server/src/main/config/modules/session-cache-hash.mod b/jetty-server/src/main/config/modules/session-cache-hash.mod index 2236405fc55..32ab705c7a2 100644 --- a/jetty-server/src/main/config/modules/session-cache-hash.mod +++ b/jetty-server/src/main/config/modules/session-cache-hash.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enable first level session cache in ConcurrentHashMap. If not enabled, sessions will use a HashSessionCache by default, so enabling diff --git a/jetty-server/src/main/config/modules/session-cache-null.mod b/jetty-server/src/main/config/modules/session-cache-null.mod index 1574ffdd73a..abdf2d7e076 100644 --- a/jetty-server/src/main/config/modules/session-cache-null.mod +++ b/jetty-server/src/main/config/modules/session-cache-null.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] A trivial SessionCache that does not actually cache sessions. diff --git a/jetty-server/src/main/config/modules/session-store-cache.mod b/jetty-server/src/main/config/modules/session-store-cache.mod index db717d4276b..72c012aad63 100644 --- a/jetty-server/src/main/config/modules/session-store-cache.mod +++ b/jetty-server/src/main/config/modules/session-store-cache.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables caching of SessionData in front of a SessionDataStore. diff --git a/jetty-server/src/main/config/modules/session-store-file.mod b/jetty-server/src/main/config/modules/session-store-file.mod index 93370659fc9..f704d619352 100644 --- a/jetty-server/src/main/config/modules/session-store-file.mod +++ b/jetty-server/src/main/config/modules/session-store-file.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables session persistent storage in files. diff --git a/jetty-server/src/main/config/modules/session-store-jdbc.mod b/jetty-server/src/main/config/modules/session-store-jdbc.mod index e154f17bb91..eab2799cf18 100644 --- a/jetty-server/src/main/config/modules/session-store-jdbc.mod +++ b/jetty-server/src/main/config/modules/session-store-jdbc.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables JDBC peristent/distributed session storage. diff --git a/jetty-server/src/main/config/modules/sessions.mod b/jetty-server/src/main/config/modules/sessions.mod index ee3d734df69..c1bcad083d0 100644 --- a/jetty-server/src/main/config/modules/sessions.mod +++ b/jetty-server/src/main/config/modules/sessions.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] The session management. By enabling this module, it allows session management to be configured via the ini templates diff --git a/jetty-server/src/main/config/modules/sessions/jdbc/datasource.mod b/jetty-server/src/main/config/modules/sessions/jdbc/datasource.mod index c4d003b0469..be665ff9f3b 100644 --- a/jetty-server/src/main/config/modules/sessions/jdbc/datasource.mod +++ b/jetty-server/src/main/config/modules/sessions/jdbc/datasource.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] JDBC Datasource connections for session storage diff --git a/jetty-server/src/main/config/modules/sessions/jdbc/driver.mod b/jetty-server/src/main/config/modules/sessions/jdbc/driver.mod index efd084a668b..eb7391a807d 100644 --- a/jetty-server/src/main/config/modules/sessions/jdbc/driver.mod +++ b/jetty-server/src/main/config/modules/sessions/jdbc/driver.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] JDBC Driver connections for session storage diff --git a/jetty-server/src/main/config/modules/ssl.mod b/jetty-server/src/main/config/modules/ssl.mod index 0c03988b2a5..65e0a708328 100644 --- a/jetty-server/src/main/config/modules/ssl.mod +++ b/jetty-server/src/main/config/modules/ssl.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables a TLS(SSL) Connector on the server. This may be used for HTTPS and/or HTTP2 by enabling diff --git a/jetty-server/src/main/config/modules/stats.mod b/jetty-server/src/main/config/modules/stats.mod index 4b80d520697..8f213c2d651 100644 --- a/jetty-server/src/main/config/modules/stats.mod +++ b/jetty-server/src/main/config/modules/stats.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enable detailed statistics collection for the server, available via JMX. diff --git a/jetty-server/src/main/config/modules/threadpool.mod b/jetty-server/src/main/config/modules/threadpool.mod index 591ddebb94f..c0201b3c7e0 100644 --- a/jetty-server/src/main/config/modules/threadpool.mod +++ b/jetty-server/src/main/config/modules/threadpool.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables the Server thread pool. diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index 1baf71c2ee8..4129af1d889 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -42,6 +42,7 @@ import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.ssl.SslConnection; import org.eclipse.jetty.util.FutureCallback; +import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; @@ -196,7 +197,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co for (ConnectionFactory factory:factories) addConnectionFactory(factory); - int cores = Runtime.getRuntime().availableProcessors(); + int cores = ProcessorUtils.availableProcessors(); if (acceptors < 0) acceptors=Math.max(1, Math.min(4,cores/8)); if (acceptors > cores) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index c523b4a9108..9ab2ba49179 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -566,7 +566,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor if (LOG.isDebugEnabled()) LOG.debug(_request.getRequestURI(), failure); else - LOG.warn("{} {}",_request.getRequestURI(), failure); + LOG.warn(_request.getRequestURI(), failure); } else { @@ -707,12 +707,14 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor return _request.getHttpInput().earlyEOF(); } - public void onBadMessage(int status, String reason) + public void onBadMessage(BadMessageException failure) { + int status = failure.getCode(); + String reason = failure.getReason(); if (status < 400 || status > 599) - status = HttpStatus.BAD_REQUEST_400; + failure = new BadMessageException(HttpStatus.BAD_REQUEST_400, reason, failure); - notifyRequestFailure(_request, new BadMessageException(status, reason)); + notifyRequestFailure(_request, failure); Action action; try @@ -721,10 +723,10 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor } catch(IllegalStateException e) { - // The bad message cannot be handled in the current state, so throw - // to hopefull somebody that can handle + // The bad message cannot be handled in the current state, + // so rethrow, hopefully somebody will be able to handle. abort(e); - throw new BadMessageException(status,reason); + throw failure; } try diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index bb61cbeb3e8..d6288290ebc 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -266,7 +266,7 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque } @Override - public void badMessage(int status, String reason) + public void badMessage(BadMessageException failure) { _httpConnection.getGenerator().setPersistent(false); try @@ -280,7 +280,7 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque LOG.ignore(e); } - onBadMessage(status, reason); + onBadMessage(failure); } @Override @@ -330,7 +330,7 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque { if (_unknownExpectation) { - badMessage(HttpStatus.EXPECTATION_FAILED_417, null); + badMessage(new BadMessageException(HttpStatus.EXPECTATION_FAILED_417)); return false; } @@ -371,7 +371,7 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque upgrade()) return true; - badMessage(HttpStatus.UPGRADE_REQUIRED_426, null); + badMessage(new BadMessageException(HttpStatus.UPGRADE_REQUIRED_426)); _httpConnection.getParser().close(); return false; } @@ -425,7 +425,10 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque if (LOG.isDebugEnabled()) LOG.debug("upgrade {} {}", this, _upgrade); - if (_upgrade != PREAMBLE_UPGRADE_H2C && (_connection == null || !_connection.contains("upgrade"))) + @SuppressWarnings("ReferenceEquality") + boolean isUpgraded_H2C = (_upgrade == PREAMBLE_UPGRADE_H2C); + + if (!isUpgraded_H2C && (_connection == null || !_connection.contains("upgrade"))) throw new BadMessageException(HttpStatus.BAD_REQUEST_400); // Find the upgrade factory @@ -462,7 +465,7 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque // Send 101 if needed try { - if (_upgrade != PREAMBLE_UPGRADE_H2C) + if (!isUpgraded_H2C) sendResponse(new MetaData.Response(HttpVersion.HTTP_1_1, HttpStatus.SWITCHING_PROTOCOLS_101, response101, 0), null, true); } catch (IOException e) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index e03823f1982..f2a992f1039 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -240,6 +240,8 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http int filled = fillRequestBuffer(); if (filled>0) bytesIn.add(filled); + else if (filled==-1 && getEndPoint().isOutputShutdown()) + close(); // Parse the request buffer. boolean handle = parseRequestBuffer(); @@ -249,13 +251,6 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http if (getEndPoint().getConnection()!=this) break; - // Handle closed parser. - if (_parser.isClose() || _parser.isClosed()) - { - close(); - break; - } - // Handle channel event if (handle) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java index 3a0dfccfad4..5914ae725d4 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java @@ -471,11 +471,6 @@ public class LocalConnector extends AbstractConnector return false; } - @Override - public void badMessage(int status, String reason) - { - } - @Override public boolean startResponse(HttpVersion version, int status, String reason) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 44e99ef7d22..6dd0d22b4a5 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -149,6 +149,18 @@ public class Request implements HttpServletRequest private static final MultiMap NO_PARAMS = new MultiMap<>(); + /* ------------------------------------------------------------ */ + /** + * Compare inputParameters to NO_PARAMS by Reference + * @param inputParameters The parameters to compare to NO_PARAMS + * @return True if the inputParameters reference is equal to NO_PARAMS otherwise False + */ + private static boolean isNoParams(MultiMap inputParameters) { + @SuppressWarnings("ReferenceEquality") + boolean is_no_params = (inputParameters==NO_PARAMS); + return is_no_params; + } + /* ------------------------------------------------------------ */ /** * Obtain the base {@link Request} instance of a {@link ServletRequest}, by @@ -392,9 +404,9 @@ public class Request implements HttpServletRequest } // Do parameters need to be combined? - if (_queryParameters==NO_PARAMS || _queryParameters.size()==0) + if (isNoParams(_queryParameters) || _queryParameters.size()==0) _parameters=_contentParameters; - else if (_contentParameters==NO_PARAMS || _contentParameters.size()==0) + else if (isNoParams(_contentParameters) || _contentParameters.size()==0) _parameters=_queryParameters; else { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java index 6031375d5c5..f95402276ea 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java @@ -225,7 +225,7 @@ public class ResourceService String pathInContext=URIUtil.addPaths(servletPath,pathInfo); - boolean endsWithSlash=(pathInfo==null?request.getServletPath():pathInfo).endsWith(URIUtil.SLASH); + boolean endsWithSlash=(pathInfo==null?servletPath:pathInfo).endsWith(URIUtil.SLASH); boolean checkPrecompressedVariants=_precompressedFormats.length > 0 && !endsWithSlash && !included && reqRanges==null; HttpContent content=null; @@ -254,7 +254,7 @@ public class ResourceService } // Strip slash? - if (endsWithSlash && pathInContext.length()>1) + if (!included && endsWithSlash && pathInContext.length()>1) { String q=request.getQueryString(); pathInContext=pathInContext.substring(0,pathInContext.length()-1); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index edce9a78d7c..de8a5e1f9f5 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -620,9 +620,9 @@ public class Response implements HttpServletResponse } - _mimeType=null; - _characterEncoding=null; _outputType = OutputType.NONE; + setContentType(null); + setCharacterEncoding(null); setHeader(HttpHeader.EXPIRES,null); setHeader(HttpHeader.LAST_MODIFIED,null); setHeader(HttpHeader.CACHE_CONTROL,null); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ResponseWriter.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ResponseWriter.java index 7a964e4feb5..47103e6257c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ResponseWriter.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ResponseWriter.java @@ -452,16 +452,30 @@ public class ResponseWriter extends PrintWriter } @Override - public PrintWriter format(Locale l, String format, Object... args) + public PrintWriter format(Locale locale, String format, Object... args) { try { + + /* If the passed locale is null then + use any locale set on the response as the default. */ + if(locale == null) + locale = _locale; + synchronized (lock) { isOpen(); - if ((_formatter == null) || (_formatter.locale() != l)) - _formatter = new Formatter(this, l); - _formatter.format(l, format, args); + + if(_formatter == null) + { + _formatter = new Formatter(this, locale); + } + else if (!_formatter.locale().equals(locale)) + { + _formatter = new Formatter(this, locale); + } + + _formatter.format(locale, format, args); } } catch (InterruptedIOException ex) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java index 9e94db9837b..67b1d30da63 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java @@ -373,17 +373,17 @@ public class Server extends HandlerWrapper implements Attributes String gitHash = Jetty.GIT_HASH; String timestamp = Jetty.BUILD_TIMESTAMP; - LOG.info("jetty-{}, build timestamp: {}, git hash: {}", getVersion(), timestamp, gitHash); - if (!Jetty.STABLE) - { - LOG.warn("THIS IS NOT A STABLE RELEASE! DO NOT USE IN PRODUCTION!"); - LOG.warn("Download a stable release from http://download.eclipse.org/jetty/"); - } - - HttpGenerator.setJettyVersion(HttpConfiguration.SERVER_VERSION); + LOG.info("jetty-{}; built: {}; git: {}; jvm {}", getVersion(), timestamp, gitHash, System.getProperty("java.runtime.version",System.getProperty("java.version"))); + if (!Jetty.STABLE) + { + LOG.warn("THIS IS NOT A STABLE RELEASE! DO NOT USE IN PRODUCTION!"); + LOG.warn("Download a stable release from http://download.eclipse.org/jetty/"); + } + + HttpGenerator.setJettyVersion(HttpConfiguration.SERVER_VERSION); MultiException mex=new MultiException(); - + // Open network connector to ensure ports are available _connectors.stream().filter(NetworkConnector.class::isInstance).map(NetworkConnector.class::cast).forEach(connector-> { @@ -396,15 +396,15 @@ public class Server extends HandlerWrapper implements Attributes mex.add(th); } }); - + // Throw now if verified start sequence and there was an open exception mex.ifExceptionThrow(); // Start the server and components, but not connectors! - // #start(LifeCycle) is overridden so that connectors are not started + // #start(LifeCycle) is overridden so that connectors are not started super.doStart(); - - // start connectors + + // start connectors for (Connector connector : _connectors) { try diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/StatisticsHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/StatisticsHandler.java index e12dc2133c6..3bb9f43d34a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/StatisticsHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/StatisticsHandler.java @@ -102,7 +102,7 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful final long elapsed = System.currentTimeMillis()-request.getTimeStamp(); long d=_requestStats.decrement(); - _requestTimeStats.set(elapsed); + _requestTimeStats.record(elapsed); updateResponse(request); @@ -184,7 +184,7 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful final long dispatched=now-start; _dispatchedStats.decrement(); - _dispatchedTimeStats.set(dispatched); + _dispatchedTimeStats.record(dispatched); if (state.isSuspended()) { @@ -197,7 +197,7 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful else if (state.isInitial()) { long d=_requestStats.decrement(); - _requestTimeStats.set(dispatched); + _requestTimeStats.record(dispatched); updateResponse(baseRequest); // If we have no more dispatches, should we signal shutdown? diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java index 62ca8ffb532..417571ad94a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java @@ -49,13 +49,102 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; /** - * A Handler that can dynamically GZIP compress responses. Unlike - * previous and 3rd party GzipFilters, this mechanism works with asynchronously - * generated responses and does not need to wrap the response or it's output - * stream. Instead it uses the efficient {@link org.eclipse.jetty.server.HttpOutput.Interceptor} mechanism. + * A Handler that can dynamically GZIP uncompress requests, and compress responses. *

- * The handler can be applied to the entire server (a gzip.mod is included in - * the distribution) or it may be applied to individual contexts. + * The GzipHandler can be applied to the entire server (a {@code gzip.mod} is included in + * the {@code jetty-home}) or it may be applied to individual contexts. + *

+ *

+ * Both Request uncompress and Response compress are gated by a configurable + * {@link DispatcherType} check on the GzipHandler. + * (This is similar in behavior to a {@link javax.servlet.Filter} configuration + * you would find in a Servlet Descriptor file ({@code WEB-INF/web.xml}) + *
(Default: {@link DispatcherType#REQUEST}). + *

+ *

+ * Requests with a {@code Content-Encoding} header with the value {@code gzip} will + * be uncompressed by a {@link GzipHttpInputInterceptor} for any API that uses + * {@link HttpServletRequest#getInputStream()} or {@link HttpServletRequest#getReader()}. + *

+ *

+ * Response compression has a number of checks before GzipHandler will perform compression. + *

+ *
    + *
  1. + * Does the request contain a {@code Accept-Encoding} header that specifies + * {@code gzip} value? + *
  2. + *
  3. + * Is the {@link HttpServletRequest#getMethod()} allowed by the configured HTTP Method Filter. + *
    (Default: {@code GET}) + *
  4. + *
  5. + * Is the incoming Path allowed by the configured Path Specs filters? + *
    (Default: all paths are allowed) + *
  6. + *
  7. + * Is the Request User-Agent allowed by the configured User-Agent filters? + *
    (Default: MSIE 6 is excluded) + *
  8. + *
  9. + * Is the Response {@code Content-Length} header present, and does its + * value meet the minimum gzip size requirements? + *
    (Default: 16 bytes. see {@link GzipHandler#DEFAULT_MIN_GZIP_SIZE}) + *
  10. + *
  11. + * Is the Request {@code Accept} header present and does it contain the + * required {@code gzip} value? + *
  12. + *
+ *

+ * When you encounter a configurable filter in the GzipHandler (method, paths, user-agent, + * mime-types, etc) that has both Included and Excluded values, note that the Included + * values always win over the Excluded values. + *

+ *

+ * Important note about Default Values: + * It is important to note that the GzipHandler will automatically configure itself from the + * MimeType present on the Server, System, and Contexts and the ultimate set of default values + * for the various filters (paths, methods, mime-types, etc) can be influenced by the + * available mime types to work with. + *

+ *

+ * ETag (or Entity Tag) information: any Request headers for {@code If-None-Match} or + * {@code If-Match} will be evaluated by the GzipHandler to determine if it was involved + * in compression of the response earlier. This is usually present as a {@code --gzip} suffix + * on the ETag that the Client User-Agent is tracking and handed to the Jetty server. + * The special {@code --gzip} suffix on the ETag is how GzipHandler knows that the content + * passed through itself, and this suffix will be stripped from the Request header values + * before the request is sent onwards to the specific webapp / servlet endpoint for + * handling. + * If a ETag is present in the Response headers, and GzipHandler is compressing the + * contents, it will add the {@code --gzip} suffix before the Response headers are committed + * and sent to the User Agent. + *

+ *

+ * This implementation relies on an Jetty internal {@link org.eclipse.jetty.server.HttpOutput.Interceptor} + * mechanism to allow for effective and efficient compression of the response on all Output API usages: + *

+ *
    + *
  • + * {@link javax.servlet.ServletOutputStream} - Obtained from {@link HttpServletResponse#getOutputStream()} + * using the traditional Blocking I/O techniques + *
  • + *
  • + * {@link javax.servlet.WriteListener} - Provided to + * {@link javax.servlet.ServletOutputStream#setWriteListener(javax.servlet.WriteListener)} + * using the new (since Servlet 3.1) Async I/O techniques + *
  • + *
  • + * {@link java.io.PrintWriter} - Obtained from {@link HttpServletResponse#getWriter()} + * using Blocking I/O techniques + *
  • + *
+ *

+ * Historically the compression of responses were accomplished via + * Servlet Filters (eg: {@code GzipFilter}) and usage of {@link javax.servlet.http.HttpServletResponseWrapper}. + * Since the introduction of Async I/O in Servlet 3.1, this older form of Gzip support + * in web applications has been problematic and bug ridden. *

*/ public class GzipHandler extends HandlerWrapper implements GzipFactory @@ -80,11 +169,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory private HttpField _vary; /** - * Instantiates a new gzip handler. - * The excluded Mime Types are initialized to common known - * images, audio, video and other already compressed types. - * The included methods is initialized to GET. - * The excluded agent patterns are set to exclude MSIE 6.0 + * Instantiates a new GzipHandler. */ public GzipHandler() { @@ -113,7 +198,10 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** + * Add excluded to the User-Agent filtering. + * * @param patterns Regular expressions matching user agents to exclude + * @see #addIncludedAgentPatterns(String...) */ public void addExcludedAgentPatterns(String... patterns) { @@ -121,7 +209,10 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** + * Add excluded to the HTTP methods filtering. + * * @param methods The methods to exclude in compression + * @see #addIncludedMethods(String...) */ public void addExcludedMethods(String... methods) { @@ -129,27 +220,47 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory _methods.exclude(m); } + /** + * Get the Set of {@link DispatcherType} that this Filter will operate on. + * + * @return the set of {@link DispatcherType} this filter will operate on + */ public EnumSet getDispatcherTypes() { return _dispatchers; } + /** + * Set of supported {@link DispatcherType} that this filter will operate on. + * + * @param dispatchers the set of {@link DispatcherType} that this filter will operate on + */ public void setDispatcherTypes(EnumSet dispatchers) { _dispatchers = dispatchers; } + /** + * Set the list of supported {@link DispatcherType} that this filter will operate on. + * + * @param dispatchers the list of {@link DispatcherType} that this filter will operate on + */ public void setDispatcherTypes(DispatcherType... dispatchers) { _dispatchers = EnumSet.copyOf(Arrays.asList(dispatchers)); } /** - * Adds mime types to the excluded list. + * Adds excluded MIME types for response filtering. + * + *

+ * Deprecation Warning: + * For backward compatibility the MIME types parameters may be comma separated strings, + * but this will not be supported in future versions of Jetty. + *

* * @param types The mime types to exclude (without charset or other parameters). - * For backward compatibility the mimetypes may be comma separated strings, but this - * will not be supported in future versions. + * @see #addIncludedMimeTypes(String...) */ public void addExcludedMimeTypes(String... types) { @@ -158,7 +269,8 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** - * Add paths to excluded paths list. + * Adds excluded Path Specs for request filtering. + * *

* There are 2 syntaxes supported, Servlet url-pattern based, and * Regex based. This means that the initial characters on the path spec @@ -181,6 +293,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory * otherwise they are absolute.
* For backward compatibility the pathspecs may be comma separated strings, but this * will not be supported in future versions. + * @see #addIncludedPaths(String...) */ public void addExcludedPaths(String... pathspecs) { @@ -189,7 +302,10 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** + * Adds included User-Agents for filtering. + * * @param patterns Regular expressions matching user agents to include + * @see #addExcludedAgentPatterns(String...) */ public void addIncludedAgentPatterns(String... patterns) { @@ -197,7 +313,10 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** - * @param methods The methods to include in compression + * Adds included HTTP Methods (eg: POST, PATCH, DELETE) for filtering. + * + * @param methods The HTTP methods to include in compression. + * @see #addExcludedMethods(String...) */ public void addIncludedMethods(String... methods) { @@ -206,7 +325,10 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** + * Is the {@link Deflater} running {@link Deflater#SYNC_FLUSH} or not. + * * @return True if {@link Deflater#SYNC_FLUSH} is used, else {@link Deflater#NO_FLUSH} + * @see #setSyncFlush(boolean) */ public boolean isSyncFlush() { @@ -214,10 +336,12 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** - *

Set the {@link Deflater} flush mode to use. {@link Deflater#SYNC_FLUSH} + * Set the {@link Deflater} flush mode to use. {@link Deflater#SYNC_FLUSH} * should be used if the application wishes to stream the data, but this may * hurt compression performance. + * * @param syncFlush True if {@link Deflater#SYNC_FLUSH} is used, else {@link Deflater#NO_FLUSH} + * @see #isSyncFlush() */ public void setSyncFlush(boolean syncFlush) { @@ -225,11 +349,12 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** - * Add included mime types. Inclusion takes precedence over - * exclusion. + * Add included MIME types for response filtering + * * @param types The mime types to include (without charset or other parameters) * For backward compatibility the mimetypes may be comma separated strings, but this * will not be supported in future versions. + * @see #addExcludedMimeTypes(String...) */ public void addIncludedMimeTypes(String... types) { @@ -238,7 +363,8 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** - * Adds paths specs to the included list. + * Add included Path Specs for filtering. + * *

* There are 2 syntaxes supported, Servlet url-pattern based, and * Regex based. This means that the initial characters on the path spec @@ -323,55 +449,109 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory return df; } - + + /** + * Get the current filter list of excluded User-Agent patterns + * + * @return the filter list of excluded User-Agent patterns + * @see #getIncludedAgentPatterns() + */ public String[] getExcludedAgentPatterns() { Set excluded=_agentPatterns.getExcluded(); return excluded.toArray(new String[excluded.size()]); } + /** + * Get the current filter list of excluded HTTP methods + * + * @return the filter list of excluded HTTP methods + * @see #getIncludedMethods() + */ public String[] getExcludedMethods() { Set excluded=_methods.getExcluded(); return excluded.toArray(new String[excluded.size()]); } + /** + * Get the current filter list of excluded MIME types + * + * @return the filter list of excluded MIME types + * @see #getIncludedMimeTypes() + */ public String[] getExcludedMimeTypes() { Set excluded=_mimeTypes.getExcluded(); return excluded.toArray(new String[excluded.size()]); } + /** + * Get the current filter list of excluded Path Specs + * + * @return the filter list of excluded Path Specs + * @see #getIncludedPaths() + */ public String[] getExcludedPaths() { Set excluded=_paths.getExcluded(); return excluded.toArray(new String[excluded.size()]); } + /** + * Get the current filter list of included User-Agent patterns + * + * @return the filter list of included User-Agent patterns + * @see #getExcludedAgentPatterns() + */ public String[] getIncludedAgentPatterns() { Set includes=_agentPatterns.getIncluded(); return includes.toArray(new String[includes.size()]); } - + + /** + * Get the current filter list of included HTTP Methods + * + * @return the filter list of included HTTP methods + * @see #getExcludedMethods() + */ public String[] getIncludedMethods() { Set includes=_methods.getIncluded(); return includes.toArray(new String[includes.size()]); } + /** + * Get the current filter list of included MIME types + * + * @return the filter list of included MIME types + * @see #getExcludedMimeTypes() + */ public String[] getIncludedMimeTypes() { Set includes=_mimeTypes.getIncluded(); return includes.toArray(new String[includes.size()]); } + /** + * Get the current filter list of included Path Specs + * + * @return the filter list of included Path Specs + * @see #getExcludedPaths() + */ public String[] getIncludedPaths() { Set includes=_paths.getIncluded(); return includes.toArray(new String[includes.size()]); } + /** + * Get the current filter list of included HTTP methods + * + * @return the filter list of included HTTP methods + * @deprecated use {@link #getIncludedMethods()} instead. (Will be removed in Jetty 10) + */ @Deprecated public String[] getMethods() { @@ -379,7 +559,11 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** - * @return minimum response size that triggers compression + * Get the minimum size, in bytes, that a response {@code Content-Length} must be + * before compression will trigger. + * + * @return minimum response size (in bytes) that triggers compression + * @see #setMinGzipSize(int) */ public int getMinGzipSize() { @@ -392,7 +576,10 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** - * @return size in bytes of the buffer to inflate compressed request, or 0 for no inflation. + * Get the size (in bytes) of the {@link java.util.zip.Inflater} buffer used to inflate + * compressed requests. + * + * @return size in bytes of the buffer, or 0 for no inflation. */ public int getInflateBufferSize() { @@ -400,7 +587,9 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** - * @param size size in bytes of the buffer to inflate compressed request, or 0 for no inflation. + * Set the size (in bytes) of the {@link java.util.zip.Inflater} buffer used to inflate comrpessed requests. + * + * @param size size in bytes of the buffer, or 0 for no inflation. */ public void setInflateBufferSize(int size) { @@ -448,6 +637,28 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory interceptor=interceptor.getNextInterceptor(); } + // Special handling for etags + for (ListIterator fields = baseRequest.getHttpFields().listIterator(); fields.hasNext();) + { + HttpField field = fields.next(); + if (field.getHeader()==HttpHeader.IF_NONE_MATCH || field.getHeader()==HttpHeader.IF_MATCH) + { + String etag = field.getValue(); + int i=etag.indexOf(CompressedContentFormat.GZIP._etagQuote); + if (i>0) + { + baseRequest.setAttribute("o.e.j.s.h.gzip.GzipHandler.etag",etag); + while (i>=0) + { + etag=etag.substring(0,i)+etag.substring(i+CompressedContentFormat.GZIP._etag.length()); + i=etag.indexOf(CompressedContentFormat.GZIP._etagQuote,i); + } + + fields.set(new HttpField(field.getHeader(),etag)); + } + } + } + // If not a supported method - no Vary because no matter what client, this URI is always excluded if (!_methods.test(baseRequest.getMethod())) { @@ -494,28 +705,6 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } } } - - // Special handling for etags - for (ListIterator fields = baseRequest.getHttpFields().listIterator(); fields.hasNext();) - { - HttpField field = fields.next(); - if (field.getHeader()==HttpHeader.IF_NONE_MATCH || field.getHeader()==HttpHeader.IF_MATCH) - { - String etag = field.getValue(); - int i=etag.indexOf(CompressedContentFormat.GZIP._etagQuote); - if (i>0) - { - baseRequest.setAttribute("o.e.j.s.h.gzip.GzipHandler.etag",etag); - while (i>=0) - { - etag=etag.substring(0,i)+etag.substring(i+CompressedContentFormat.GZIP._etag.length()); - i=etag.indexOf(CompressedContentFormat.GZIP._etagQuote,i); - } - - fields.set(new HttpField(field.getHeader(),etag)); - } - } - } HttpOutput.Interceptor orig_interceptor = out.getInterceptor(); try @@ -535,6 +724,8 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** + * Test if the provided User-Agent is allowed based on the User-Agent filters. + * * @param ua the user agent * @return whether compressing is allowed for the given user agent */ @@ -546,6 +737,12 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory return _agentPatterns.test(ua); } + /** + * Test if the provided MIME type is allowed based on the MIME type filters. + * + * @param mimetype the MIME type to test + * @return true if allowed, false otherwise + */ @Override public boolean isMimeTypeGzipable(String mimetype) { @@ -553,6 +750,8 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** + * Test if the provided Request URI is allowed based on the Path Specs filters. + * * @param requestURI the request uri * @return whether compressing is allowed for the given the path */ @@ -577,6 +776,8 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** + * Set the Check if {@code *.gz} file for the incoming file exists. + * * @param checkGzExists whether to check if a static gz file exists for * the resource that the DefaultServlet may serve as precompressed. */ @@ -586,7 +787,10 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** + * Set the Compression level that {@link Deflater} uses. + * * @param compressionLevel The compression level to use to initialize {@link Deflater#setLevel(int)} + * @see Deflater#setLevel(int) */ public void setCompressionLevel(int compressionLevel) { @@ -594,7 +798,10 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** - * @param patterns Regular expressions matching user agents to exclude + * Set the excluded filter list of User-Agent patterns (replacing any previously set) + * + * @param patterns Regular expressions list matching user agents to exclude + * @see #setIncludedAgentPatterns(String...) */ public void setExcludedAgentPatterns(String... patterns) { @@ -603,7 +810,10 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** + * Set the excluded filter list of HTTP methods (replacing any previously set) + * * @param methods the HTTP methods to exclude + * @see #setIncludedMethods(String...) */ public void setExcludedMethods(String... methods) { @@ -612,7 +822,10 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** + * Set the excluded filter list of MIME types (replacing any previously set) + * * @param types The mime types to exclude (without charset or other parameters) + * @see #setIncludedMimeTypes(String...) */ public void setExcludedMimeTypes(String... types) { @@ -621,9 +834,12 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** - * @param pathspecs Path specs (as per servlet spec) to exclude. If a + * Set the excluded filter list of Path specs (replacing any previously set) + * + * @param pathspecs Path specs (as per servlet spec) to exclude. If a * ServletContext is available, the paths are relative to the context path, * otherwise they are absolute. + * @see #setIncludedPaths(String...) */ public void setExcludedPaths(String... pathspecs) { @@ -632,7 +848,10 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** + * Set the included filter list of User-Agent patterns (replacing any previously set) + * * @param patterns Regular expressions matching user agents to include + * @see #setExcludedAgentPatterns(String...) */ public void setIncludedAgentPatterns(String... patterns) { @@ -641,7 +860,10 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** + * Set the included filter list of HTTP methods (replacing any previously set) + * * @param methods The methods to include in compression + * @see #setExcludedMethods(String...) */ public void setIncludedMethods(String... methods) { @@ -650,9 +872,10 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** - * Sets included mime types. Inclusion takes precedence over exclusion. + * Set the included filter list of MIME types (replacing any previously set) * * @param types The mime types to include (without charset or other parameters) + * @see #setExcludedMimeTypes(String...) */ public void setIncludedMimeTypes(String... types) { @@ -661,11 +884,12 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } /** - * Set the path specs to include. Inclusion takes precedence over exclusion. + * Set the included filter list of Path specs (replacing any previously set) * * @param pathspecs Path specs (as per servlet spec) to include. If a * ServletContext is available, the paths are relative to the context path, * otherwise they are absolute + * @see #setExcludedPaths(String...) */ public void setIncludedPaths(String... pathspecs) { @@ -683,21 +907,45 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory _minGzipSize = minGzipSize; } + /** + * Set the included filter list of HTTP Methods (replacing any previously set) + * + * @param csvMethods the list of methods, CSV format + * @see #setExcludedMethodList(String) + */ public void setIncludedMethodList(String csvMethods) { setIncludedMethods(StringUtil.csvSplit(csvMethods)); } + /** + * Get the included filter list of HTTP methods in CSV format + * + * @return the included filter list of HTTP methods in CSV format + * @see #getExcludedMethodList() + */ public String getIncludedMethodList() { return String.join(",", getIncludedMethods()); } + /** + * Set the excluded filter list of HTTP Methods (replacing any previously set) + * + * @param csvMethods the list of methods, CSV format + * @see #setIncludedMethodList(String) + */ public void setExcludedMethodList(String csvMethods) { setExcludedMethods(StringUtil.csvSplit(csvMethods)); } + /** + * Get the excluded filter list of HTTP methods in CSV format + * + * @return the excluded filter list of HTTP methods in CSV format + * @see #getIncludedMethodList() + */ public String getExcludedMethodList() { return String.join(",", getExcludedMethods()); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java index 5a7c46fee23..f793222103d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java @@ -18,8 +18,6 @@ package org.eclipse.jetty.server.session; -import static java.lang.Math.round; - import java.io.IOException; import java.util.Arrays; import java.util.Collections; @@ -63,9 +61,11 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.statistic.CounterStatistic; import org.eclipse.jetty.util.statistic.SampleStatistic; +import org.eclipse.jetty.util.thread.Locker.Lock; import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; import org.eclipse.jetty.util.thread.Scheduler; -import org.eclipse.jetty.util.thread.Locker.Lock; + +import static java.lang.Math.round; /* ------------------------------------------------------------ */ /** @@ -1235,7 +1235,7 @@ public class SessionHandler extends ScopedHandler if (session != null) { - _sessionTimeStats.set(round((System.currentTimeMillis() - session.getSessionData().getCreated())/1000.0)); + _sessionTimeStats.record(round((System.currentTimeMillis() - session.getSessionData().getCreated())/1000.0)); session.finishInvalidate(); } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectionOpenCloseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectionOpenCloseTest.java index 97bf92123de..f71c3a24496 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectionOpenCloseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectionOpenCloseTest.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; +import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -42,9 +43,11 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.toolchain.test.AdvancedRunner; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.annotation.Slow; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -224,11 +227,9 @@ public class ConnectionOpenCloseTest extends AbstractHttpTest "\r\n").getBytes(StandardCharsets.UTF_8)); output.flush(); - InputStream inputStream = socket.getInputStream(); - HttpTester.Response response = HttpTester.parseResponse(inputStream); - Assert.assertEquals(200, response.getStatus()); - - Assert.assertEquals(-1, inputStream.read()); + // Read to EOF + String response = BufferUtil.toString(ByteBuffer.wrap(IO.readBytes(socket.getInputStream()))); + assertThat(response,Matchers.containsString("200 OK")); socket.close(); Assert.assertTrue(openLatch.await(5, TimeUnit.SECONDS)); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ErrorHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ErrorHandlerTest.java index eff49a97385..64a3f9b8087 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ErrorHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ErrorHandlerTest.java @@ -19,30 +19,34 @@ package org.eclipse.jetty.server; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.startsWith; -import static org.junit.Assert.*; +import static org.junit.Assert.assertThat; import java.io.IOException; +import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpTester; +import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.ErrorHandler; -import org.eclipse.jetty.toolchain.test.AdvancedRunner; -import org.junit.After; -import org.junit.Before; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; -import org.junit.runner.RunWith; -@RunWith(AdvancedRunner.class) public class ErrorHandlerTest { - Server server; - LocalConnector connector; + static Server server; + static LocalConnector connector; - @Before - public void before() throws Exception + @BeforeClass + public static void before() throws Exception { server = new Server(); connector = new LocalConnector(server); @@ -72,17 +76,36 @@ public class ErrorHandlerTest .append("}"); break; } + case "text/plain": + { + baseRequest.setHandled(true); + response.setContentType("text/plain"); + response.getOutputStream().print(response.getContentType()); + break; + } default: super.generateAcceptableResponse(baseRequest,request,response,code,message,mimeType); } } }); + server.setHandler(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + if(target.startsWith("/charencoding/")) + { + response.setCharacterEncoding("utf-8"); + response.sendError(404); + } + } + }); server.start(); } - @After - public void after() throws Exception + @AfterClass + public static void after() throws Exception { server.stop(); } @@ -260,4 +283,19 @@ public class ErrorHandlerTest assertThat(response,containsString("Content-Type: text/json")); } + @Test + public void testCharEncoding() throws Exception + { + String rawResponse = connector.getResponse( + "GET /charencoding/foo HTTP/1.1\r\n"+ + "Host: Localhost\r\n"+ + "Accept: text/plain\r\n"+ + "\r\n"); + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + + assertThat("Response status code", response.getStatus(), is(404)); + HttpField contentType = response.getField(HttpHeader.CONTENT_TYPE); + assertThat("Response Content-Type", contentType, is(notNullValue())); + assertThat("Response Content-Type value", contentType.getValue(), not(containsString("null"))); + } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/LowResourcesMonitorTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/LowResourcesMonitorTest.java index ddf14534eff..121ef30d5cf 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/LowResourcesMonitorTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/LowResourcesMonitorTest.java @@ -218,28 +218,28 @@ public class LowResourcesMonitorTest @Test public void testMaxLowResourceTime() throws Exception { - _lowResourcesMonitor.setMaxLowResourcesTime(2000); + _lowResourcesMonitor.setMaxLowResourcesTime(5000); Assert.assertFalse(_lowResourcesMonitor.isLowOnResources()); try(Socket socket0 = new Socket("localhost",_connector.getLocalPort())) { _lowResourcesMonitor.setMaxMemory(1); - Thread.sleep(1200); + Thread.sleep(2400); Assert.assertTrue(_lowResourcesMonitor.isLowOnResources()); try(Socket socket1 = new Socket("localhost",_connector.getLocalPort())) { - Thread.sleep(1200); + Thread.sleep(2400); Assert.assertTrue(_lowResourcesMonitor.isLowOnResources()); Assert.assertEquals(-1,socket0.getInputStream().read()); socket1.getOutputStream().write("G".getBytes(StandardCharsets.UTF_8)); - Thread.sleep(1200); + Thread.sleep(2400); Assert.assertTrue(_lowResourcesMonitor.isLowOnResources()); socket1.getOutputStream().write("E".getBytes(StandardCharsets.UTF_8)); - Thread.sleep(1200); + Thread.sleep(2400); Assert.assertTrue(_lowResourcesMonitor.isLowOnResources()); Assert.assertEquals(-1,socket1.getInputStream().read()); } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index 3dddc7c732b..9d0021130a7 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -63,6 +63,7 @@ import org.eclipse.jetty.server.session.Session; import org.eclipse.jetty.server.session.SessionData; import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.toolchain.test.AdvancedRunner; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.thread.Scheduler; import org.eclipse.jetty.util.thread.TimerScheduler; @@ -112,10 +113,13 @@ public class ResponseTest private Server _server; private HttpChannel _channel; + private ByteBuffer _content = BufferUtil.allocate(16*1024); @Before public void init() throws Exception { + BufferUtil.clear(_content); + _server = new Server(); Scheduler _scheduler = new TimerScheduler(); HttpConfiguration config = new HttpConfiguration(); @@ -139,6 +143,12 @@ public class ResponseTest @Override public void send(MetaData.Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback) { + if(BufferUtil.hasContent(content)) + { + BufferUtil.append(_content, content); + } + + if (_channelError==null) callback.succeeded(); else @@ -172,6 +182,7 @@ public class ResponseTest { return false; } + }); } @@ -364,6 +375,54 @@ public class ResponseTest assertTrue(response.toString().indexOf("charset=utf-8") > 0); } + @Test + public void testLocaleFormat() throws Exception + { + Response response = getResponse(); + + ContextHandler context = new ContextHandler(); + context.addLocaleEncoding(Locale.ENGLISH.toString(), "ISO-8859-1"); + context.addLocaleEncoding(Locale.ITALIAN.toString(), "ISO-8859-2"); + response.getHttpChannel().getRequest().setContext(context.getServletContext()); + + response.setLocale(java.util.Locale.ITALIAN); + + PrintWriter out = response.getWriter(); + + out.format("TestA1 %,.2f%n", 1234567.89); + out.format("TestA2 %,.2f%n", 1234567.89); + + out.format((java.util.Locale)null,"TestB1 %,.2f%n", 1234567.89); + out.format((java.util.Locale)null,"TestB2 %,.2f%n", 1234567.89); + + out.format(Locale.ENGLISH,"TestC1 %,.2f%n", 1234567.89); + out.format(Locale.ENGLISH,"TestC2 %,.2f%n", 1234567.89); + + out.format(Locale.ITALIAN,"TestD1 %,.2f%n", 1234567.89); + out.format(Locale.ITALIAN,"TestD2 %,.2f%n", 1234567.89); + + out.close(); + + /* Test A */ + Assert.assertThat(BufferUtil.toString(_content),Matchers.containsString("TestA1 1.234.567,89")); + Assert.assertThat(BufferUtil.toString(_content),Matchers.containsString("TestA2 1.234.567,89")); + + /* Test B */ + Assert.assertThat(BufferUtil.toString(_content),Matchers.containsString("TestB1 1.234.567,89")); + Assert.assertThat(BufferUtil.toString(_content),Matchers.containsString("TestB2 1.234.567,89")); + + /* Test C */ + Assert.assertThat(BufferUtil.toString(_content),Matchers.containsString("TestC1 1,234,567.89")); + Assert.assertThat(BufferUtil.toString(_content),Matchers.containsString("TestC2 1,234,567.89")); + + /* Test D */ + Assert.assertThat(BufferUtil.toString(_content),Matchers.containsString("TestD1 1.234.567,89")); + Assert.assertThat(BufferUtil.toString(_content),Matchers.containsString("TestD2 1.234.567,89")); + + + } + + @Test public void testContentTypeCharacterEncoding() throws Exception { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ThreadStarvationTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ThreadStarvationTest.java index 4d3c90cce11..8cd7fa3671e 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ThreadStarvationTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ThreadStarvationTest.java @@ -325,13 +325,21 @@ public class ThreadStarvationTest byte buf[] = new byte[1024]; - while((len = in.read(buf,0,buf.length)) != -1) + try { - for(int x=0; x entry=_servletHandler.getMappedServlet(welcome_in_context); - if (entry!=null && entry.getResource()!=_defaultHolder && + @SuppressWarnings("ReferenceEquality") + boolean isDefaultHolder = (entry.getResource()!=_defaultHolder); + if (entry!=null && isDefaultHolder && (_welcomeServlets || (_welcomeExactServlets && entry.getPathSpec().getDeclaration().equals(welcome_in_context)))) welcome_servlet=welcome_in_context; diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java index 83338af8692..3458838bf42 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java @@ -1513,7 +1513,9 @@ public class ServletHandler extends ScopedHandler boolean found = false; for (ServletHolder s:_servlets) { - if (s == holder) + @SuppressWarnings("ReferenceEquality") + boolean foundServletHolder = (s == holder); + if (foundServletHolder) found = true; } return found; diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java index fdf20d9e8bc..fd67f91eaa3 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java @@ -47,13 +47,13 @@ import org.eclipse.jetty.http.HttpTester; import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.gzip.GzipHandler; -import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.IO; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Before; import org.junit.Test; +@SuppressWarnings("serial") public class GzipHandlerTest { private static final String __content = @@ -151,6 +151,17 @@ public class GzipHandlerTest writer.write(__content); } } + + @Override + protected void doDelete(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException + { + String ifm = req.getHeader("If-Match"); + if (ifm!=null && ifm.equals(__contentETag)) + response.sendError(HttpServletResponse.SC_NO_CONTENT); + else + response.sendError(HttpServletResponse.SC_NOT_MODIFIED); + } + } public static class EchoServlet extends HttpServlet @@ -347,6 +358,43 @@ public class GzipHandlerTest assertThat(response.get("ETag"),is(__contentETagGzip)); } + + @Test + public void testDeleteETagGzipHandler() throws Exception + { + HttpTester.Request request = HttpTester.newRequest(); + HttpTester.Response response; + + request.setMethod("DELETE"); + request.setURI("/ctx/content"); + request.setVersion("HTTP/1.0"); + request.setHeader("Host","tester"); + request.setHeader("If-Match","WrongEtag--gzip"); + request.setHeader("accept-encoding","gzip"); + + response = HttpTester.parseResponse(_connector.getResponse(request.generate())); + + assertThat(response.getStatus(),is(HttpServletResponse.SC_NOT_MODIFIED)); + assertThat(response.get("Content-Encoding"),not(Matchers.equalToIgnoringCase("gzip"))); + + + request = HttpTester.newRequest(); + request.setMethod("DELETE"); + request.setURI("/ctx/content"); + request.setVersion("HTTP/1.0"); + request.setHeader("Host","tester"); + request.setHeader("If-Match",__contentETagGzip); + request.setHeader("accept-encoding","gzip"); + + response = HttpTester.parseResponse(_connector.getResponse(request.generate())); + + assertThat(response.getStatus(),is(HttpServletResponse.SC_NO_CONTENT)); + assertThat(response.get("Content-Encoding"),not(Matchers.equalToIgnoringCase("gzip"))); + } + + + + @Test public void testForwardGzipHandler() throws Exception { diff --git a/jetty-servlets/src/main/config/modules/servlets.mod b/jetty-servlets/src/main/config/modules/servlets.mod index 5e1c84fc272..07cd5fd046d 100644 --- a/jetty-servlets/src/main/config/modules/servlets.mod +++ b/jetty-servlets/src/main/config/modules/servlets.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Puts a collection of jetty utility servlets and filters on the server classpath (CGI, CrossOriginFilter, DosFilter, diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java index 70545d2c0a8..f61208695ee 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java @@ -54,7 +54,8 @@ import org.eclipse.jetty.util.log.Logger; *

allowedOrigins
*
a comma separated list of origins that are * allowed to access the resources. Default value is *, meaning all - * origins. + * origins. Note that using wild cards can result in security problems + * for requests identifying hosts that do not exist. *

* If an allowed origin contains one or more * characters (for example * http://*.domain.com), then "*" characters are converted to ".*", "." diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DataRateLimitedServlet.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DataRateLimitedServlet.java index efa66326812..aaf2bf1709b 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DataRateLimitedServlet.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DataRateLimitedServlet.java @@ -37,6 +37,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.HttpOutput; +import org.eclipse.jetty.util.ProcessorUtils; /** * A servlet that uses the Servlet 3.1 asynchronous IO API to server @@ -78,7 +79,7 @@ public class DataRateLimitedServlet extends HttpServlet if (tmp!=null) pauseNS=TimeUnit.MILLISECONDS.toNanos(Integer.parseInt(tmp)); tmp = getInitParameter("pool"); - int pool=tmp==null?Runtime.getRuntime().availableProcessors():Integer.parseInt(tmp); + int pool=tmp==null?ProcessorUtils.availableProcessors():Integer.parseInt(tmp); // Create and start a shared scheduler. scheduler=new ScheduledThreadPoolExecutor(pool); diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java index 5b334a3f19c..f3c4253cb0d 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java @@ -383,7 +383,7 @@ public class DoSFilter implements Filter // or if we were woken up we insist or we fail. Boolean throttled = (Boolean)request.getAttribute(__THROTTLED); long throttleMs = getThrottleMs(); - if (throttled != Boolean.TRUE && throttleMs > 0) + if (!Boolean.TRUE.equals(throttled) && throttleMs > 0) { int priority = getPriority(request, tracker); request.setAttribute(__THROTTLED, Boolean.TRUE); @@ -401,7 +401,7 @@ public class DoSFilter implements Filter } Boolean resumed = (Boolean)request.getAttribute(_resumed); - if (resumed == Boolean.TRUE) + if (Boolean.TRUE.equals(resumed)) { // We were resumed, we wait for the next pass. _passes.acquire(); @@ -446,7 +446,7 @@ public class DoSFilter implements Filter { ServletRequest candidate = asyncContext.getRequest(); Boolean suspended = (Boolean)candidate.getAttribute(_suspended); - if (suspended == Boolean.TRUE) + if (Boolean.TRUE.equals(suspended)) { if (LOG.isDebugEnabled()) LOG.debug("Resuming {}", request); diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java index 2d4b0febd95..65d00182e79 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java @@ -173,7 +173,7 @@ public class QoSFilter implements Filter { request.setAttribute(_suspended, Boolean.FALSE); Boolean resumed = (Boolean)request.getAttribute(_resumed); - if (resumed == Boolean.TRUE) + if (Boolean.TRUE.equals(resumed)) { _passes.acquire(); accepted = true; @@ -224,7 +224,7 @@ public class QoSFilter implements Filter { ServletRequest candidate = asyncContext.getRequest(); Boolean suspended = (Boolean)candidate.getAttribute(_suspended); - if (suspended == Boolean.TRUE) + if (Boolean.TRUE.equals(suspended)) { candidate.setAttribute(_resumed, Boolean.TRUE); asyncContext.dispatch(); diff --git a/jetty-spdy/pom.xml b/jetty-spdy/pom.xml deleted file mode 100644 index 9ec565c9d74..00000000000 --- a/jetty-spdy/pom.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - org.eclipse.jetty - jetty-project - 9.2.23-SNAPSHOT - - - 4.0.0 - org.eclipse.jetty.spdy - spdy-parent - pom - Jetty :: SPDY :: Parent - http://www.eclipse.org/jetty - - - spdy-core - spdy-client - spdy-server - spdy-http-common - spdy-http-server - spdy-http-client-transport - spdy-example-webapp - spdy-alpn-tests - - - - - npn - - 1.7 - - - - - - - - - - - maven-pmd-plugin - - true - - - - org.apache.felix - maven-bundle-plugin - true - - - - manifest - - - - org.eclipse.jetty.spdy.*;version="9.1" - org.eclipse.jetty.*;version="[9.0,10.0)",* - <_nouses>true - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - ${project.build.outputDirectory}/META-INF/MANIFEST.MF - - - - - - - - - org.eclipse.jetty.toolchain - jetty-test-helper - test - - - - diff --git a/jetty-spdy/spdy-alpn-tests/pom.xml b/jetty-spdy/spdy-alpn-tests/pom.xml deleted file mode 100644 index d0931a162c1..00000000000 --- a/jetty-spdy/spdy-alpn-tests/pom.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - org.eclipse.jetty.spdy - spdy-parent - 9.2.23-SNAPSHOT - - - 4.0.0 - spdy-alpn-tests - Jetty :: SPDY :: ALPN Tests - - - - - maven-dependency-plugin - - - copy - generate-resources - - copy - - - - - org.mortbay.jetty.alpn - alpn-boot - ${alpn.version} - jar - false - ${project.build.directory}/alpn - - - - - - - - maven-surefire-plugin - - -Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar - - - - - - - - org.eclipse.jetty.alpn - alpn-api - ${alpn.api.version} - provided - - - org.eclipse.jetty - jetty-alpn-server - ${project.version} - provided - - - org.eclipse.jetty - jetty-server - ${project.version} - test - - - org.eclipse.jetty.spdy - spdy-server - ${project.version} - test - - - org.eclipse.jetty.spdy - spdy-http-server - ${project.version} - test - - - org.eclipse.jetty.spdy - spdy-http-server - ${project.version} - tests - test - - - junit - junit - test - - - - diff --git a/jetty-spdy/spdy-client/pom.xml b/jetty-spdy/spdy-client/pom.xml deleted file mode 100644 index 6f0bb90e92b..00000000000 --- a/jetty-spdy/spdy-client/pom.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - org.eclipse.jetty.spdy - spdy-parent - 9.2.23-SNAPSHOT - - - 4.0.0 - spdy-client - Jetty :: SPDY :: Client Binding - - - ${project.groupId}.client - - - http://www.eclipse.org/jetty - - - - org.apache.felix - maven-bundle-plugin - true - - - - manifest - - - - org.eclipse.jetty.spdy.client;version="9.1" - !org.eclipse.jetty.npn,!org.eclipse.jetty.alpn,org.eclipse.jetty.*;version="[9.0,10.0)",* - - - - - - - - - - - org.eclipse.jetty.spdy - spdy-core - ${project.version} - - - org.eclipse.jetty - jetty-alpn-client - ${project.version} - - - org.eclipse.jetty.alpn - alpn-api - ${alpn.api.version} - provided - - - org.eclipse.jetty.npn - npn-api - ${npn.api.version} - provided - - - - diff --git a/jetty-spdy/spdy-core/pom.xml b/jetty-spdy/spdy-core/pom.xml deleted file mode 100644 index b35715e3259..00000000000 --- a/jetty-spdy/spdy-core/pom.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - org.eclipse.jetty.spdy - spdy-parent - 9.2.23-SNAPSHOT - - - 4.0.0 - spdy-core - Jetty :: SPDY :: Core - - - ${project.groupId}.core - - - - - org.eclipse.jetty - jetty-util - ${project.version} - - - org.eclipse.jetty - jetty-io - ${project.version} - - - org.mockito - mockito-core - test - - - - diff --git a/jetty-spdy/spdy-example-webapp/pom.xml b/jetty-spdy/spdy-example-webapp/pom.xml deleted file mode 100644 index 2f806788368..00000000000 --- a/jetty-spdy/spdy-example-webapp/pom.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - org.eclipse.jetty.spdy - spdy-parent - 9.2.23-SNAPSHOT - - 4.0.0 - spdy-example-webapp - war - Jetty :: SPDY :: HTTP Web Application - - - - - org.eclipse.jetty - jetty-maven-plugin - ${project.version} - - 8888 - quit - - -Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${npn.version}/npn-boot-${npn.version}.jar - - ${basedir}/src/main/config/example-jetty-spdy.xml - / - - run - run-war - deploy - start - stop - - - - - org.eclipse.jetty.spdy - spdy-http-server - ${project.version} - - - - - - - - - proxy - - - - org.eclipse.jetty - jetty-maven-plugin - ${project.version} - - 8888 - quit - - -Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${npn.version}/npn-boot-${npn.version}.jar - - ${basedir}/src/main/config/example-jetty-spdy-proxy.xml - / - - run - run-war - deploy - start - stop - - - - - org.eclipse.jetty.spdy - spdy-http-server - ${project.version} - - - - - - - - - diff --git a/jetty-spdy/spdy-http-client-transport/pom.xml b/jetty-spdy/spdy-http-client-transport/pom.xml deleted file mode 100644 index 0c6ad340246..00000000000 --- a/jetty-spdy/spdy-http-client-transport/pom.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - org.eclipse.jetty.spdy - spdy-parent - 9.2.23-SNAPSHOT - - - 4.0.0 - spdy-http-client-transport - Jetty :: SPDY :: HTTP Client Transport - - - ${project.groupId}.client.http - - - - - - org.apache.felix - maven-bundle-plugin - true - - - - manifest - - - - org.eclipse.jetty.spdy.client.http;version="9.1" - !org.eclipse.jetty.npn,org.eclipse.jetty.*;version="[9.0,10.0)",* - - - - - - - - - - - org.eclipse.jetty - jetty-client - ${project.version} - - - org.eclipse.jetty.spdy - spdy-client - ${project.version} - - - org.eclipse.jetty.spdy - spdy-http-common - ${project.version} - - - - org.eclipse.jetty - jetty-server - ${project.version} - test - - - org.eclipse.jetty.spdy - spdy-http-server - ${project.version} - test - - - - diff --git a/jetty-spdy/spdy-http-common/pom.xml b/jetty-spdy/spdy-http-common/pom.xml deleted file mode 100644 index c0a97d9d21f..00000000000 --- a/jetty-spdy/spdy-http-common/pom.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - org.eclipse.jetty.spdy - spdy-parent - 9.2.23-SNAPSHOT - - - 4.0.0 - spdy-http-common - Jetty :: SPDY :: HTTP Common - - - ${project.groupId}.http.common - - - - - - org.apache.felix - maven-bundle-plugin - true - - - - manifest - - - - org.eclipse.jetty.spdy.http;version="9.1" - !org.eclipse.jetty.npn,org.eclipse.jetty.*;version="[9.0,10.0)",* - - - - - - - - - - - org.eclipse.jetty.spdy - spdy-core - ${project.version} - - - - diff --git a/jetty-spdy/spdy-http-server/pom.xml b/jetty-spdy/spdy-http-server/pom.xml deleted file mode 100644 index 4757f3633c1..00000000000 --- a/jetty-spdy/spdy-http-server/pom.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - org.eclipse.jetty.spdy - spdy-parent - 9.2.23-SNAPSHOT - - 4.0.0 - spdy-http-server - Jetty :: SPDY :: HTTP Server - - - ${project.groupId}.http.server - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - package - - single - - - - config - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - artifact-jars - - jar - test-jar - - - - - - org.apache.felix - maven-bundle-plugin - true - - - - manifest - - - - org.eclipse.jetty.spdy.server.http;version="9.1", - org.eclipse.jetty.spdy.server.proxy;version="9.1" - - !org.eclipse.jetty.npn,org.eclipse.jetty.*;version="[9.0,10.0)",* - - <_nouses>true - - - - - - - - - - - org.eclipse.jetty.spdy - spdy-http-common - ${project.version} - - - org.eclipse.jetty.spdy - spdy-server - ${project.version} - - - org.eclipse.jetty - jetty-client - ${project.version} - - - org.eclipse.jetty - jetty-servlet - ${project.version} - test - - - org.eclipse.jetty - jetty-servlets - ${project.version} - test - - - org.eclipse.jetty.npn - npn-api - ${npn.api.version} - test - - - org.eclipse.jetty - jetty-continuation - ${project.version} - test - - - org.mockito - mockito-core - test - - - - diff --git a/jetty-spdy/spdy-server/pom.xml b/jetty-spdy/spdy-server/pom.xml deleted file mode 100644 index 71440708754..00000000000 --- a/jetty-spdy/spdy-server/pom.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - org.eclipse.jetty.spdy - spdy-parent - 9.2.23-SNAPSHOT - - - 4.0.0 - spdy-server - Jetty :: SPDY :: Server Binding - - - ${project.groupId}.server - - - http://www.eclipse.org/jetty - - - - org.apache.felix - maven-bundle-plugin - true - - - - manifest - - - - org.eclipse.jetty.spdy.server;version="9.1" - org.eclipse.jetty.alpn;resolution:=optional,org.eclipse.jetty.alpn.server;resolution:=optional, org.eclipse.jetty.npn;resolution:=optional,org.eclipse.jetty.*;version="[9.0,10.0)",* - <_nouses>true - - - - - - - - - - - org.eclipse.jetty.spdy - spdy-core - ${project.version} - - - org.eclipse.jetty.spdy - spdy-client - ${project.version} - - - org.eclipse.jetty - jetty-server - ${project.version} - - - org.eclipse.jetty.npn - npn-api - ${npn.api.version} - provided - - - org.eclipse.jetty.alpn - alpn-api - ${alpn.api.version} - provided - - - - diff --git a/jetty-spring/src/main/config/modules/spring.mod b/jetty-spring/src/main/config/modules/spring.mod index cd52a5dd70e..0f7762de4b4 100644 --- a/jetty-spring/src/main/config/modules/spring.mod +++ b/jetty-spring/src/main/config/modules/spring.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enable spring configuration processing so all jetty style xml files can optionally be written as spring beans diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java index 1bf7c8fef2a..59c7dc72a46 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java @@ -39,7 +39,6 @@ import java.net.SocketTimeoutException; import java.nio.file.Path; import java.util.List; import java.util.Locale; -import java.util.regex.Matcher; import org.eclipse.jetty.start.Props.Prop; import org.eclipse.jetty.start.config.CommandLineConfigSource; @@ -295,18 +294,18 @@ public class Main args.parse(baseHome.getConfigSources()); Props props = baseHome.getConfigSources().getProps(); - Props.Prop home = props.getProp(BaseHome.JETTY_HOME); + Prop home = props.getProp(BaseHome.JETTY_HOME); if (!args.getProperties().containsKey(BaseHome.JETTY_HOME)) args.getProperties().setProperty(home); args.getProperties().setProperty(BaseHome.JETTY_HOME+".uri", normalizeURI(baseHome.getHomePath().toUri().toString()), - home.origin); - Props.Prop base = props.getProp(BaseHome.JETTY_BASE); + home.source); + Prop base = props.getProp(BaseHome.JETTY_BASE); if (!args.getProperties().containsKey(BaseHome.JETTY_BASE)) args.getProperties().setProperty(base); args.getProperties().setProperty(BaseHome.JETTY_BASE+".uri", normalizeURI(baseHome.getBasePath().toUri().toString()), - base.origin); + base.source); // ------------------------------------------------------------ // 3) Module Registration @@ -426,25 +425,8 @@ public class Main { for (ConfigSource config : baseHome.getConfigSources()) { - System.out.printf("ConfigSource %s%n",config.getId()); for (StartIni ini : config.getStartInis()) - { - for (String line : ini.getAllLines()) - { - Matcher m = Module.SET_PROPERTY.matcher(line); - if (m.matches() && m.groupCount()==3) - { - String name = m.group(2); - String value = m.group(3); - Prop p = args.getProperties().getProp(name); - if (p!=null && ("#".equals(m.group(1)) || !value.equals(p.value))) - { - ini.update(baseHome,args.getProperties()); - break; - } - } - } - } + ini.update(baseHome,args.getProperties()); } } @@ -512,10 +494,10 @@ public class Main private void doStop(StartArgs args) { - Props.Prop stopHostProp = args.getProperties().getProp("STOP.HOST", true); - Props.Prop stopPortProp = args.getProperties().getProp("STOP.PORT", true); - Props.Prop stopKeyProp = args.getProperties().getProp("STOP.KEY", true); - Props.Prop stopWaitProp = args.getProperties().getProp("STOP.WAIT", true); + Prop stopHostProp = args.getProperties().getProp("STOP.HOST", true); + Prop stopPortProp = args.getProperties().getProp("STOP.PORT", true); + Prop stopKeyProp = args.getProperties().getProp("STOP.KEY", true); + Prop stopWaitProp = args.getProperties().getProp("STOP.WAIT", true); String stopHost = "127.0.0.1"; int stopPort = -1; diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java index 45e1581a553..7bec2fe5b90 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java @@ -37,7 +37,6 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import org.eclipse.jetty.start.Props.Prop; -import org.eclipse.jetty.start.config.CommandLineConfigSource; /** * Represents a Module metadata, as defined in Jetty. @@ -527,9 +526,12 @@ public class Module implements Comparable if (m.matches() && m.groupCount()==3) { String name = m.group(2); + String value = m.group(3); Prop p = props.getProp(name); - if (p!=null && p.origin.startsWith(CommandLineConfigSource.ORIGIN_CMD_LINE)) + + if (p!=null && (p.source==null || !p.source.endsWith("?=")) && ("#".equals(m.group(1)) || !value.equals(p.value))) { + System.err.printf("%s == %s :: %s%n",name,value,p.source); StartLog.info("%-15s property set %s=%s",this._name,name,p.value); out.printf("%s=%s%n",name,p.value); } diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java index 0879311d473..69bcad311d9 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java @@ -305,7 +305,7 @@ public class Modules implements Iterable { for (Module p:providers) { - if (p!=module && p.isEnabled()) + if (!p.equals(module) && p.isEnabled()) { // If the already enabled module is transitive and this enable is not if (p.isTransitive() && !transitive) @@ -364,8 +364,8 @@ public class Modules implements Iterable } // If a provider is already enabled, then add a transitive enable - if (providers.stream().filter(Module::isEnabled).count()!=0) - providers.stream().filter(m->m.isEnabled()&&m!=module).forEach(m->enable(newlyEnabled,m,"transitive provider of "+dependsOn+" for "+module.getName(),true)); + if (providers.stream().filter(Module::isEnabled).count()>0) + providers.stream().filter(m->m.isEnabled()&&!m.equals(module)).forEach(m->enable(newlyEnabled,m,"transitive provider of "+dependsOn+" for "+module.getName(),true)); else { // Is there an obvious default? diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java index c1dc1e13c34..73f9775ef6a 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java @@ -48,20 +48,13 @@ public final class Props implements Iterable { public String key; public String value; - public String origin; - public Prop overrides; + public String source; - public Prop(String key, String value, String origin) + public Prop(String key, String value, String source) { this.key = key; this.value = value; - this.origin = origin; - } - - public Prop(String key, String value, String origin, Prop overrides) - { - this(key,value,origin); - this.overrides = overrides; + this.source = source; } @Override @@ -72,15 +65,12 @@ public final class Props implements Iterable builder.append(key); builder.append(", value="); builder.append(value); - builder.append(", origin="); - builder.append(origin); - builder.append(", overrides="); - builder.append(overrides); + builder.append(", source="); + builder.append(source); builder.append("]"); return builder.toString(); } } - public static final String ORIGIN_SYSPROP = ""; public static String getValue(String arg) @@ -342,16 +332,7 @@ public final class Props implements Iterable public void setProperty(String key, String value, String origin) { - Prop prop = props.get(key); - if (prop == null) - { - prop = new Prop(key,value,origin); - } - else - { - prop = new Prop(key,value,origin,prop); - } - props.put(key,prop); + props.put(key,new Prop(key,value,origin)); } public int size() diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java index ed06cfc48a7..bf389e2f71a 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java @@ -35,7 +35,6 @@ import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; -import java.util.function.Function; import org.eclipse.jetty.start.Props.Prop; import org.eclipse.jetty.start.config.ConfigSource; @@ -123,9 +122,6 @@ public class StartArgs /** Map of enabled modules to the source of where that activation occurred */ Map> sources = new HashMap<>(); - /** Map of properties to where that property was declared */ - private Map propertySource = new HashMap<>(); - /** List of all active [files] sections from enabled modules */ private List files = new ArrayList<>(); @@ -148,7 +144,7 @@ public class StartArgs private List propertyFiles = new ArrayList<>(); private Props properties = new Props(); - private Set systemPropertyKeys = new HashSet<>(); + private Map systemPropertySource = new HashMap<>(); private List rawLibs = new ArrayList<>(); // jetty.base - build out commands @@ -205,12 +201,6 @@ public class StartArgs } } - public void addSystemProperty(String key, String value) - { - this.systemPropertyKeys.add(key); - System.setProperty(key,value); - } - private void addUniqueXmlFile(String xmlRef, Path xmlfile) throws IOException { if (!FS.canReadFile(xmlfile)) @@ -337,7 +327,7 @@ public class StartArgs List sortedKeys = new ArrayList<>(); for (Prop prop : properties) { - if (prop.origin.equals(Props.ORIGIN_SYSPROP)) + if (prop.source.equals(Props.ORIGIN_SYSPROP)) { continue; // skip } @@ -369,16 +359,7 @@ public class StartArgs { System.out.printf(" %s = %s%n",key,prop.value); if (StartLog.isDebugEnabled()) - { - System.out.printf(" origin: %s%n",prop.origin); - while (prop.overrides != null) - { - prop = prop.overrides; - System.out.printf(" (overrides)%n"); - System.out.printf(" %s = %s%n",key,prop.value); - System.out.printf(" origin: %s%n",prop.origin); - } - } + System.out.printf(" origin: %s%n",prop.source); } } @@ -388,26 +369,25 @@ public class StartArgs System.out.println("System Properties:"); System.out.println("------------------"); - if (systemPropertyKeys.isEmpty()) + if (systemPropertySource.keySet().isEmpty()) { System.out.println(" (no system properties specified)"); return; } List sortedKeys = new ArrayList<>(); - sortedKeys.addAll(systemPropertyKeys); + sortedKeys.addAll(systemPropertySource.keySet()); Collections.sort(sortedKeys); for (String key : sortedKeys) - { - String value = System.getProperty(key); - System.out.printf(" %s = %s%n",key,value); - } + dumpSystemProperty(key); } private void dumpSystemProperty(String key) { - System.out.printf(" %s = %s%n",key,System.getProperty(key)); + String value = System.getProperty(key); + String source = systemPropertySource.get(key); + System.out.printf(" %s = %s (%s)%n",key,value,source); } /** @@ -418,20 +398,20 @@ public class StartArgs */ private void ensureSystemPropertySet(String key) { - if (systemPropertyKeys.contains(key)) + if (systemPropertySource.containsKey(key)) { return; // done } if (properties.containsKey(key)) { - String val = properties.expand(properties.getString(key)); - if (val == null) - { - return; // no value to set - } + Prop prop = properties.getProp(key); + if (prop==null) + return; // no value set; + + String val = properties.expand(prop.value); // setup system property - systemPropertyKeys.add(key); + systemPropertySource.put(key,"property:"+prop.source); System.setProperty(key,val); } } @@ -446,7 +426,7 @@ public class StartArgs { StartLog.debug("Expanding System Properties"); - for (String key : systemPropertyKeys) + for (String key : systemPropertySource.keySet()) { String value = properties.getString(key); if (value!=null) @@ -588,11 +568,8 @@ public class StartArgs String key = assign[0]; String value = assign.length==1?"":assign[1]; - Property p = processProperty(key,value,"modules",k->{return System.getProperty(k);}); - if (p!=null) - { - cmd.addRawArg("-D"+p.key+"="+getProperties().expand(p.value)); - } + Prop p = processSystemProperty(key,value,null); + cmd.addRawArg("-D"+p.key+"="+getProperties().expand(p.value)); } else { @@ -601,7 +578,7 @@ public class StartArgs } // System Properties - for (String propKey : systemPropertyKeys) + for (String propKey : systemPropertySource.keySet()) { String value = System.getProperty(propKey); cmd.addEqualsArg("-D" + propKey,value); @@ -737,7 +714,7 @@ public class StartArgs public boolean hasSystemProperties() { - for (String key : systemPropertyKeys) + for (String key : systemPropertySource.keySet()) { // ignored keys if ("jetty.home".equals(key) || "jetty.base".equals(key) || "main.class".equals(key)) @@ -1096,13 +1073,10 @@ public class StartArgs String key = assign[0]; String value = assign.length==1?"":assign[1]; - Property p = processProperty(key,value,source,k->{return System.getProperty(k);}); - if (p!=null) - { - systemPropertyKeys.add(p.key); - setProperty(p.key,p.value,p.source); - System.setProperty(p.key,p.value); - } + Prop p = processSystemProperty(key,value,source); + systemPropertySource.put(p.key,p.source); + setProperty(p.key,p.value,p.source); + System.setProperty(p.key,p.value); return; } @@ -1124,11 +1098,8 @@ public class StartArgs String key = arg.substring(0,equals); String value = arg.substring(equals + 1); - Property p = processProperty(key,value,source,k->{return getProperties().getString(k);}); - if (p!=null) - { - setProperty(p.key,p.value,p.source); - } + processAndSetProperty(key,value,source); + return; } @@ -1157,41 +1128,69 @@ public class StartArgs throw new UsageException(UsageException.ERR_BAD_ARG,"Unrecognized argument: \"%s\" in %s",arg,source); } - protected Property processProperty(String key,String value,String source, Function getter) + protected Prop processSystemProperty(String key, String value, String source) { if (key.endsWith("+")) { key = key.substring(0,key.length() - 1); - String orig = getter.apply(key); + String orig = System.getProperty(key); if (orig == null || orig.isEmpty()) { if (value.startsWith(",")) value = value.substring(1); } + else + { + value = orig + value; + if (source!=null && systemPropertySource.containsKey(key)) + source = systemPropertySource.get(key) + "," + source; + } + } + else if (key.endsWith("?")) + { + key = key.substring(0,key.length() - 1); + String preset = System.getProperty(key); + if (preset!=null) + { + value = preset; + source = systemPropertySource.get(key); + } + else if (source!=null) + source = source+"?="; + } + + return new Prop(key, value, source); + } + + protected void processAndSetProperty(String key,String value,String source) + { + if (key.endsWith("+")) + { + key = key.substring(0,key.length() - 1); + Prop orig = getProperties().getProp(key); + if (orig == null) + { + if (value.startsWith(",")) + value = value.substring(1); + } else { - value = orig + value; - source = propertySource.get(key) + "," + source; + value = orig.value + value; + source = orig.source + "," + source; } } - if (key.endsWith("?")) + else if (key.endsWith("?")) { key = key.substring(0,key.length() - 1); - String preset = getter.apply(key); + Prop preset = getProperties().getProp(key); if (preset!=null) - { + return; + + if (source!=null) source = source+"?="; - value = preset; - } - } - else if (propertySource.containsKey(key)) - { - if (!propertySource.get(key).endsWith("[ini]")) - StartLog.warn("Property %s in %s already set in %s",key,source,propertySource.get(key)); - propertySource.put(key,source); } - return new Property(key,value,source); + setProperty(key,value,source); } private void enableModules(String source, List moduleNames) @@ -1266,12 +1265,11 @@ public class StartArgs try { JavaVersion ver = JavaVersion.parse(value); - properties.setProperty("java.version",ver.getVersion(),source); properties.setProperty("java.version.platform",Integer.toString(ver.getPlatform()),source); - properties.setProperty("java.version.major",Integer.toString(ver.getMajor()),source); - properties.setProperty("java.version.minor",Integer.toString(ver.getMinor()),source); - properties.setProperty("java.version.micro",Integer.toString(ver.getMicro()),source); - properties.setProperty("java.version.update",Integer.toString(ver.getUpdate()),source); + // @deprecated - below will be removed in Jetty 10.x + properties.setProperty("java.version.major", Integer.toString(ver.getMajor()), "Deprecated"); + properties.setProperty("java.version.minor", Integer.toString(ver.getMinor()), "Deprecated"); + properties.setProperty("java.version.micro", Integer.toString(ver.getMicro()), "Deprecated"); } catch (Throwable x) { @@ -1303,22 +1301,4 @@ public class StartArgs return builder.toString(); } - static class Property - { - String key; - String value; - String source; - public Property(String key, String value, String source) - { - this.key = key; - this.value = value; - this.source = source; - } - - @Override - public String toString() - { - return String.format("%s=%s(%s)",key,value,source); - } - } } diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/StartIni.java b/jetty-start/src/main/java/org/eclipse/jetty/start/StartIni.java index ed212777a2b..08a2ddf43ad 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/StartIni.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/StartIni.java @@ -92,7 +92,9 @@ public class StartIni extends TextFile update = update.substring(0,update.lastIndexOf(".")); String source = baseHome.toShortForm(getFile()); - try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(getFile(),StandardCharsets.UTF_8,StandardOpenOption.TRUNCATE_EXISTING,StandardOpenOption.CREATE))) + PrintWriter writer = null; + + try { for (String line : getAllLines()) { @@ -102,23 +104,42 @@ public class StartIni extends TextFile String name = m.group(2); String value = m.group(3); Prop p = props.getProp(name); - if (p!=null && ("#".equals(m.group(1)) || !value.equals(p.value))) + + if (p!=null && (p.source==null || !p.source.endsWith("?=")) && ("#".equals(m.group(1)) || !value.equals(p.value))) { + if (writer==null) + { + writer = new PrintWriter(Files.newBufferedWriter(getFile(),StandardCharsets.UTF_8,StandardOpenOption.TRUNCATE_EXISTING,StandardOpenOption.CREATE)); + for (String l : getAllLines()) + { + if (line.equals(l)) + break; + writer.println(l); + } + } + StartLog.info("%-15s property updated %s=%s",update,name,p.value); writer.printf("%s=%s%n",name,p.value); } - else + else if (writer!=null) { writer.println(line); } } - else + else if (writer!=null) { writer.println(line); } } } + finally + { + if (writer!=null) + { + StartLog.info("%-15s updated %s",update,source); + writer.close(); + } + } - StartLog.info("%-15s updated %s",update,source); } } diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java index b366117adea..6d19755d068 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java @@ -142,7 +142,7 @@ public class ConfigurationAssert "jetty.home.uri".equals(name) || "jetty.base.uri".equals(name) || "user.dir".equals(name) || - prop.origin.equals(Props.ORIGIN_SYSPROP) || + prop.source.equals(Props.ORIGIN_SYSPROP) || name.startsWith("java.")) { // strip these out from assertion, to make assertions easier. diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/PropsTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/PropsTest.java index b5605391f53..8b70512485d 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/PropsTest.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/PropsTest.java @@ -20,7 +20,6 @@ package org.eclipse.jetty.start; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; @@ -36,7 +35,7 @@ public class PropsTest assertThat(prefix,prop,notNullValue()); assertThat(prefix + ".key",prop.key,is(expectedKey)); assertThat(prefix + ".value",prop.value,is(expectedValue)); - assertThat(prefix + ".origin",prop.origin,is(expectedOrigin)); + assertThat(prefix + ".origin",prop.source,is(expectedOrigin)); } @Test @@ -49,7 +48,6 @@ public class PropsTest Prop prop = props.getProp("java.io.tmpdir"); assertProp("System Prop",prop,"java.io.tmpdir",expected,Props.ORIGIN_SYSPROP); - assertThat("System Prop.overrides",prop.overrides,nullValue()); } @Test @@ -63,25 +61,6 @@ public class PropsTest Prop prop = props.getProp("name"); assertProp(prefix,prop,"name","jetty",FROM_TEST); - assertThat(prefix + ".overrides",prop.overrides,nullValue()); - } - - @Test - public void testOverride() - { - Props props = new Props(); - props.setProperty("name","jetty",FROM_TEST); - props.setProperty("name","altjetty","(Alt-Jetty)"); - - String prefix = "Overriden"; - assertThat(prefix,props.getString("name"),is("altjetty")); - - Prop prop = props.getProp("name"); - assertProp(prefix,prop,"name","altjetty","(Alt-Jetty)"); - Prop older = prop.overrides; - assertThat(prefix + ".overrides",older,notNullValue()); - assertProp(prefix + ".overridden",older,"name","jetty",FROM_TEST); - assertThat(prefix + ".overridden",older.overrides,nullValue()); } @Test diff --git a/jetty-start/src/test/resources/dist-home/modules/main.mod b/jetty-start/src/test/resources/dist-home/modules/main.mod index 853030567d4..730db51631c 100644 --- a/jetty-start/src/test/resources/dist-home/modules/main.mod +++ b/jetty-start/src/test/resources/dist-home/modules/main.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Example of a module diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_144.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_144.mod deleted file mode 100644 index fdd3868701d..00000000000 --- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_144.mod +++ /dev/null @@ -1,8 +0,0 @@ -[name] -protonego-boot - -[files] -http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar|lib/alpn/alpn-boot-8.1.11.v20170118.jar - -[exec] --Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar diff --git a/jetty-start/src/test/resources/usecases/parameterized.addToStart.assert.txt b/jetty-start/src/test/resources/usecases/parameterized.addToStart.assert.txt index b31ef3c69c5..46344a3d993 100644 --- a/jetty-start/src/test/resources/usecases/parameterized.addToStart.assert.txt +++ b/jetty-start/src/test/resources/usecases/parameterized.addToStart.assert.txt @@ -12,6 +12,7 @@ PROP|main.prop=value0 PROP|name=value PROP|name0=changed0 PROP|name1=changed1 +PROP|name2=two PROP|property=value PROP|property0=value0 diff --git a/jetty-start/src/test/resources/usecases/parameterized.commands.assert.txt b/jetty-start/src/test/resources/usecases/parameterized.commands.assert.txt index b31ef3c69c5..46344a3d993 100644 --- a/jetty-start/src/test/resources/usecases/parameterized.commands.assert.txt +++ b/jetty-start/src/test/resources/usecases/parameterized.commands.assert.txt @@ -12,6 +12,7 @@ PROP|main.prop=value0 PROP|name=value PROP|name0=changed0 PROP|name1=changed1 +PROP|name2=two PROP|property=value PROP|property0=value0 diff --git a/jetty-start/src/test/resources/usecases/parameterized.update.assert.txt b/jetty-start/src/test/resources/usecases/parameterized.update.assert.txt index 4e4570e277d..a581efdad66 100644 --- a/jetty-start/src/test/resources/usecases/parameterized.update.assert.txt +++ b/jetty-start/src/test/resources/usecases/parameterized.update.assert.txt @@ -10,8 +10,9 @@ LIB|${jetty.home}/lib/other.jar # The Properties we expect (order is irrelevant) PROP|main.prop=value0 PROP|name=value -PROP|name0=changed0 +PROP|name0=updated0 PROP|name1=changed1 +PROP|name2=two PROP|property=value PROP|property0=changed0 PROP|property1=changed1 diff --git a/jetty-start/src/test/resources/usecases/parameterized.update.prepare.txt b/jetty-start/src/test/resources/usecases/parameterized.update.prepare.txt index 6ecc31c4e0d..86a278a1792 100644 --- a/jetty-start/src/test/resources/usecases/parameterized.update.prepare.txt +++ b/jetty-start/src/test/resources/usecases/parameterized.update.prepare.txt @@ -8,3 +8,4 @@ name1=changed1 --update-ini property0=changed0 property1=changed1 +name0=updated0 \ No newline at end of file diff --git a/jetty-start/src/test/resources/usecases/parameterized/modules/parameterized.mod b/jetty-start/src/test/resources/usecases/parameterized/modules/parameterized.mod index c243eb73efa..7d09c7e9fe9 100644 --- a/jetty-start/src/test/resources/usecases/parameterized/modules/parameterized.mod +++ b/jetty-start/src/test/resources/usecases/parameterized/modules/parameterized.mod @@ -4,7 +4,10 @@ main [ini] name=value +name0?=default +name2?=two [ini-template] name0=value0 # name1=value1 +# name2=too diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket-forwarded.mod b/jetty-unixsocket/src/main/config/modules/unixsocket-forwarded.mod index 3af8240d7c2..4aacc4f27cc 100644 --- a/jetty-unixsocket/src/main/config/modules/unixsocket-forwarded.mod +++ b/jetty-unixsocket/src/main/config/modules/unixsocket-forwarded.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Adds a forwarded request customizer to the HTTP configuration used by the Unix Domain Socket connector, for use when behind a proxy operating diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod b/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod index d86002780f3..e8f17427237 100644 --- a/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod +++ b/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Adds a HTTP protocol support to the Unix Domain Socket connector. It should be used when a proxy is forwarding either HTTP or decrypted diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod b/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod index 396fdc1f609..7de5cb019fb 100644 --- a/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod +++ b/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Adds a HTTP2C connetion factory to the Unix Domain Socket Connector It can be used when either the proxy forwards direct diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket-proxy-protocol.mod b/jetty-unixsocket/src/main/config/modules/unixsocket-proxy-protocol.mod index a8186366ba8..c30c59bfe7f 100644 --- a/jetty-unixsocket/src/main/config/modules/unixsocket-proxy-protocol.mod +++ b/jetty-unixsocket/src/main/config/modules/unixsocket-proxy-protocol.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables the proxy protocol on the Unix Domain Socket Connector http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket-secure.mod b/jetty-unixsocket/src/main/config/modules/unixsocket-secure.mod index 4284943804b..a66ed83f716 100644 --- a/jetty-unixsocket/src/main/config/modules/unixsocket-secure.mod +++ b/jetty-unixsocket/src/main/config/modules/unixsocket-secure.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enable a secure request customizer on the HTTP Configuration used by the Unix Domain Socket Connector. diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket.mod b/jetty-unixsocket/src/main/config/modules/unixsocket.mod index 2bdb57df920..84a45d21831 100644 --- a/jetty-unixsocket/src/main/config/modules/unixsocket.mod +++ b/jetty-unixsocket/src/main/config/modules/unixsocket.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enables a Unix Domain Socket Connector that can receive requests from a local proxy and/or SSL offloader (eg haproxy) in either diff --git a/jetty-util/src/main/config/modules/console-capture.mod b/jetty-util/src/main/config/modules/console-capture.mod index b4cda2351e4..e91e2baa93b 100644 --- a/jetty-util/src/main/config/modules/console-capture.mod +++ b/jetty-util/src/main/config/modules/console-capture.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Redirects JVMs console stderr and stdout to a log file, including output from Jetty's default StdErrLog logging. diff --git a/jetty-util/src/main/config/modules/jcl-slf4j.mod b/jetty-util/src/main/config/modules/jcl-slf4j.mod index ce109a259e9..cbe80839ca1 100644 --- a/jetty-util/src/main/config/modules/jcl-slf4j.mod +++ b/jetty-util/src/main/config/modules/jcl-slf4j.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Provides a Java Commons Logging (JCL) binding to SLF4J logging. diff --git a/jetty-util/src/main/config/modules/jul-impl.mod b/jetty-util/src/main/config/modules/jul-impl.mod index b691795b6e1..7ac22f79fb2 100644 --- a/jetty-util/src/main/config/modules/jul-impl.mod +++ b/jetty-util/src/main/config/modules/jul-impl.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Configures the Java Util Logging mechanism diff --git a/jetty-util/src/main/config/modules/jul-slf4j.mod b/jetty-util/src/main/config/modules/jul-slf4j.mod index 64397022f18..cf8317ec64e 100644 --- a/jetty-util/src/main/config/modules/jul-slf4j.mod +++ b/jetty-util/src/main/config/modules/jul-slf4j.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Provides a Java Util Loggin binding to SLF4J logging. diff --git a/jetty-util/src/main/config/modules/log4j-impl.mod b/jetty-util/src/main/config/modules/log4j-impl.mod index dcc8fa52613..5be5f77f385 100644 --- a/jetty-util/src/main/config/modules/log4j-impl.mod +++ b/jetty-util/src/main/config/modules/log4j-impl.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Provides a Log4j v1.2 API and implementation. To receive jetty logs enable the jetty-slf4j and slf4j-log4j modules. diff --git a/jetty-util/src/main/config/modules/log4j2-api.mod b/jetty-util/src/main/config/modules/log4j2-api.mod index da7a609b047..3c4e4e82e8f 100644 --- a/jetty-util/src/main/config/modules/log4j2-api.mod +++ b/jetty-util/src/main/config/modules/log4j2-api.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Provides the Log4j v2 API diff --git a/jetty-util/src/main/config/modules/log4j2-impl.mod b/jetty-util/src/main/config/modules/log4j2-impl.mod index e069ecd62b1..d95806e7c54 100644 --- a/jetty-util/src/main/config/modules/log4j2-impl.mod +++ b/jetty-util/src/main/config/modules/log4j2-impl.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Provides a Log4j v2 implementation. To receive jetty logs enable the jetty-slf4j, slf4j-log4j and log4j-log4j2 modules. diff --git a/jetty-util/src/main/config/modules/log4j2-slf4j.mod b/jetty-util/src/main/config/modules/log4j2-slf4j.mod index f8085253127..6c351779b10 100644 --- a/jetty-util/src/main/config/modules/log4j2-slf4j.mod +++ b/jetty-util/src/main/config/modules/log4j2-slf4j.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Provides a Log4j v2 binding to SLF4J logging. diff --git a/jetty-util/src/main/config/modules/logback-impl.mod b/jetty-util/src/main/config/modules/logback-impl.mod index e001ca0a76e..cc8569ef692 100644 --- a/jetty-util/src/main/config/modules/logback-impl.mod +++ b/jetty-util/src/main/config/modules/logback-impl.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Provides the logback core implementation and logback-access diff --git a/jetty-util/src/main/config/modules/logging-jetty.mod b/jetty-util/src/main/config/modules/logging-jetty.mod index 85a89b6d102..65f926d3a89 100644 --- a/jetty-util/src/main/config/modules/logging-jetty.mod +++ b/jetty-util/src/main/config/modules/logging-jetty.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Configure jetty logging mechanism. Provides a ${jetty.base}/resources/jetty-logging.properties. diff --git a/jetty-util/src/main/config/modules/logging-jul.mod b/jetty-util/src/main/config/modules/logging-jul.mod index a2dbe05e804..bc0d414ba73 100644 --- a/jetty-util/src/main/config/modules/logging-jul.mod +++ b/jetty-util/src/main/config/modules/logging-jul.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Configure jetty logging to use Java Util Logging (jul) SLF4J is used as the core logging mechanism. diff --git a/jetty-util/src/main/config/modules/logging-log4j.mod b/jetty-util/src/main/config/modules/logging-log4j.mod index a19d24aaeab..75b2f29b36d 100644 --- a/jetty-util/src/main/config/modules/logging-log4j.mod +++ b/jetty-util/src/main/config/modules/logging-log4j.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Configure jetty logging to use Log4j Logging SLF4J is used as the core logging mechanism. diff --git a/jetty-util/src/main/config/modules/logging-log4j2.mod b/jetty-util/src/main/config/modules/logging-log4j2.mod index f946abef861..34bea9b9be6 100644 --- a/jetty-util/src/main/config/modules/logging-log4j2.mod +++ b/jetty-util/src/main/config/modules/logging-log4j2.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Configure jetty logging to use log4j version 2 SLF4J is used as the core logging mechanism. diff --git a/jetty-util/src/main/config/modules/logging-logback.mod b/jetty-util/src/main/config/modules/logging-logback.mod index b5c72046981..f6699c0257d 100644 --- a/jetty-util/src/main/config/modules/logging-logback.mod +++ b/jetty-util/src/main/config/modules/logging-logback.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Configure jetty logging to use Logback Logging. SLF4J is used as the core logging mechanism. diff --git a/jetty-util/src/main/config/modules/logging-slf4j.mod b/jetty-util/src/main/config/modules/logging-slf4j.mod index a9174b86ddc..aac12a87ef7 100644 --- a/jetty-util/src/main/config/modules/logging-slf4j.mod +++ b/jetty-util/src/main/config/modules/logging-slf4j.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Configure jetty logging to use slf4j. Any slf4j-impl implementation is used diff --git a/jetty-util/src/main/config/modules/slf4j-api.mod b/jetty-util/src/main/config/modules/slf4j-api.mod index 12054fc5e14..b490f3f20d0 100644 --- a/jetty-util/src/main/config/modules/slf4j-api.mod +++ b/jetty-util/src/main/config/modules/slf4j-api.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Provides SLF4J API. Requires a slf4j implementation (eg slf4j-simple-impl) otherwise a noop implementation is used. diff --git a/jetty-util/src/main/config/modules/slf4j-jul.mod b/jetty-util/src/main/config/modules/slf4j-jul.mod index 26bf8b786ae..a0e072daab2 100644 --- a/jetty-util/src/main/config/modules/slf4j-jul.mod +++ b/jetty-util/src/main/config/modules/slf4j-jul.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Provides a SLF4J binding to Java Util Logging (JUL) logging. diff --git a/jetty-util/src/main/config/modules/slf4j-log4j.mod b/jetty-util/src/main/config/modules/slf4j-log4j.mod index 391061ee193..d61ded58678 100644 --- a/jetty-util/src/main/config/modules/slf4j-log4j.mod +++ b/jetty-util/src/main/config/modules/slf4j-log4j.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Provides a SLF4J binding to the Log4j v1.2 API logging. diff --git a/jetty-util/src/main/config/modules/slf4j-log4j2.mod b/jetty-util/src/main/config/modules/slf4j-log4j2.mod index d1e327b40b9..4a5d104eea5 100644 --- a/jetty-util/src/main/config/modules/slf4j-log4j2.mod +++ b/jetty-util/src/main/config/modules/slf4j-log4j2.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Provides a SLF4J binding to Log4j v2 logging. diff --git a/jetty-util/src/main/config/modules/slf4j-logback.mod b/jetty-util/src/main/config/modules/slf4j-logback.mod index 3ea375bb916..f9ebe8bfe1d 100644 --- a/jetty-util/src/main/config/modules/slf4j-logback.mod +++ b/jetty-util/src/main/config/modules/slf4j-logback.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Provides a SLF4J binding to Logback logging. diff --git a/jetty-util/src/main/config/modules/slf4j-simple-impl.mod b/jetty-util/src/main/config/modules/slf4j-simple-impl.mod index 168ff76e6f3..bc1b7fd92f8 100644 --- a/jetty-util/src/main/config/modules/slf4j-simple-impl.mod +++ b/jetty-util/src/main/config/modules/slf4j-simple-impl.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Provides SLF4J simple logging implementation. To receive jetty logs enable the jetty-slf4j module. diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/AtomicBiInteger.java b/jetty-util/src/main/java/org/eclipse/jetty/util/AtomicBiInteger.java new file mode 100644 index 00000000000..948262836e6 --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/AtomicBiInteger.java @@ -0,0 +1,291 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * An AtomicLong with additional methods to treat it has + * two hi/lo integers. + */ +public class AtomicBiInteger extends AtomicLong +{ + /** + * @return the hi integer value + */ + public int getHi() + { + return getHi(get()); + } + + /** + * @return the lo integer value + */ + public int getLo() + { + return getLo(get()); + } + + /** + * Atomically set the hi integer value without changing + * the lo value. + * @param hi the new hi value + * @return the hi int value + */ + public int setHi(int hi) + { + while(true) + { + long encoded = get(); + long update = encodeHi(encoded,hi); + if (compareAndSet(encoded,update)) + return getHi(encoded); + } + } + + /** + * Atomically set the lo integer value without changing + * the hi value. + * @param lo the new lo value + */ + public int setLo(int lo) + { + while(true) + { + long encoded = get(); + long update = encodeLo(encoded,lo); + if (compareAndSet(encoded,update)) + return getLo(encoded); + } + } + + /** + * Set the hi and lo integer values. + * @param hi the new hi value + * @param lo the new lo value + */ + public void set(int hi, int lo) + { + set(encode(hi,lo)); + } + + /** + * Atomically sets the hi int value to the given updated value + * only if the current value {@code ==} the expected value. + * Concurrent changes to the lo value result in a retry. + * @param expect the expected value + * @param hi the new value + * @return {@code true} if successful. False return indicates that + * the actual value was not equal to the expected value. + */ + public boolean compareAndSetHi(int expect, int hi) + { + while(true) + { + long encoded = get(); + if (getHi(encoded)!=expect) + return false; + long update = encodeHi(encoded,hi); + if (compareAndSet(encoded,update)) + return true; + } + } + + /** + * Atomically sets the lo int value to the given updated value + * only if the current value {@code ==} the expected value. + * Concurrent changes to the hi value result in a retry. + * @param expect the expected value + * @param lo the new value + * @return {@code true} if successful. False return indicates that + * the actual value was not equal to the expected value. + */ + public boolean compareAndSetLo(int expect, int lo) + { + while(true) + { + long encoded = get(); + if (getLo(encoded)!=expect) + return false; + long update = encodeLo(encoded,lo); + if (compareAndSet(encoded,update)) + return true; + } + } + + /** + * Atomically sets the values to the given updated values + * only if the current encoded value {@code ==} the expected value. + * @param expect the expected encoded values + * @param hi the new hi value + * @param lo the new lo value + * @return {@code true} if successful. False return indicates that + * the actual value was not equal to the expected value. + */ + public boolean compareAndSet(long expect, int hi, int lo) + { + long encoded = get(); + long update = encode(hi,lo); + return compareAndSet(encoded,update); + } + + /** + * Atomically sets the values to the given updated values + * only if the current encoded value {@code ==} the expected value. + * @param expectHi the expected hi values + * @param hi the new hi value + * @param expectLo the expected lo values + * @param lo the new lo value + * @return {@code true} if successful. False return indicates that + * the actual value was not equal to the expected value. + */ + public boolean compareAndSet(int expectHi, int hi, int expectLo, int lo) + { + long encoded = encode(expectHi,expectLo); + long update = encode(hi,lo); + return compareAndSet(encoded,update); + } + + /** + * Atomically updates the current hi value with the results of + * applying the given delta, returning the updated value. + * + * @param delta the delta to apply + * @return the updated value + */ + public int updateHi(int delta) + { + while(true) + { + long encoded = get(); + int hi = getHi(encoded)+delta; + long update = encodeHi(encoded,hi); + if (compareAndSet(encoded,update)) + return hi; + } + } + + /** + * Atomically updates the current lo value with the results of + * applying the given delta, returning the updated value. + * + * @param delta the delta to apply + * @return the updated value + */ + public int updateLo(int delta) + { + while(true) + { + long encoded = get(); + int lo = getLo(encoded)+delta; + long update = encodeLo(encoded,lo); + if (compareAndSet(encoded,update)) + return lo; + } + } + + /** + * Atomically updates the current values with the results of + * applying the given deltas. + * + * @param deltaHi the delta to apply to the hi value + * @param deltaLo the delta to apply to the lo value + */ + public void update(int deltaHi, int deltaLo) + { + while(true) + { + long encoded = get(); + long update = encode(getHi(encoded)+deltaHi, getLo(encoded)+deltaLo); + if (compareAndSet(encoded,update)) + return; + } + } + + /** + * Get a hi int value from an encoded long + * @param encoded the encoded value + * @return the hi int value + */ + public static int getHi(long encoded) + { + return (int) ((encoded>>32)&0xFFFF_FFFFl); + } + + /** + * Get a lo int value from an encoded long + * @param encoded the encoded value + * @return the lo int value + */ + public static int getLo(long encoded) + { + return (int) (encoded&0xFFFF_FFFFl); + } + + /** + * Encode hi and lo int values into a long + * @param hi the hi int value + * @param lo the lo int value + * @return the encoded value + * + */ + public static long encode(int hi, int lo) + { + long h = ((long)hi)&0xFFFF_FFFFl; + long l = ((long)lo)&0xFFFF_FFFFl; + long encoded = (h<<32)+l; + return encoded; + } + + + /** + * Encode hi int values into an already encoded long + * @param encoded the encoded value + * @param hi the hi int value + * @return the encoded value + * + */ + public static long encodeHi(long encoded, int hi) + { + long h = ((long)hi)&0xFFFF_FFFFl; + long l = encoded&0xFFFF_FFFFl; + encoded = (h<<32)+l; + return encoded; + } + + /** + * Encode lo int values into an already encoded long + * @param encoded the encoded value + * @param lo the lo int value + * @return the encoded value + * + */ + public static long encodeLo(long encoded, int lo) + { + long h = (encoded>>32)&0xFFFF_FFFFl; + long l = ((long)lo)&0xFFFF_FFFFl; + encoded = (h<<32)+l; + return encoded; + } + + + + + +} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java index cba8dac91bc..a35cbb43881 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java @@ -238,6 +238,17 @@ public class BufferUtil } } + /** + * @param buf the buffer to check + * @return true if buf is equal to EMPTY_BUFFER + */ + public static boolean isTheEmptyBuffer(ByteBuffer buf) + { + @SuppressWarnings("ReferenceEquality") + boolean isTheEmptyBuffer_ = (buf == EMPTY_BUFFER); + return isTheEmptyBuffer_; + } + /* ------------------------------------------------------------ */ /** Check for an empty or null buffer. * @param buf the buffer to check diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Fields.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Fields.java index 9c360b4b8cc..23b8e0713d3 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Fields.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Fields.java @@ -251,6 +251,7 @@ public class Fields implements Iterable this.values = Collections.unmodifiableList(list); } + @SuppressWarnings("ReferenceEquality") public boolean equals(Field that, boolean caseSensitive) { if (this == that) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/JavaVersion.java b/jetty-util/src/main/java/org/eclipse/jetty/util/JavaVersion.java index ae9201906c3..f1cbd74b718 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/JavaVersion.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/JavaVersion.java @@ -32,98 +32,34 @@ public class JavaVersion * Acceptable values should correspond to those returned by JavaVersion.getPlatform(). */ public static final String JAVA_TARGET_PLATFORM = "org.eclipse.jetty.javaTargetPlatform"; + + public static final JavaVersion VERSION = parse(System.getProperty("java.version")); - /** Regex for Java version numbers */ - private static final String VNUM = "(?[1-9][0-9]*(?:(?:\\.0)*\\.[0-9]+)*)"; - private static final String UPDATE = "(?:(?_)(?[0-9]+))?"; - private static final String PRE = "(?:-(?

[a-zA-Z0-9]+))?";
-    private static final String BUILD = "(?:(?\\+)(?[0-9]+))?";
-    private static final String OPT = "(?:-(?[-a-zA-Z0-9.~]+))?";
-
-    private static final String VSTR_FORMAT = VNUM + UPDATE + PRE + BUILD + OPT;
-
-    static final Pattern VSTR_PATTERN = Pattern.compile(VSTR_FORMAT);
-    
-    public static final JavaVersion VERSION = parse(System.getProperty("java.runtime.version",System.getProperty("java.version")));
-
     public static JavaVersion parse(String v) 
-    {
-        Matcher m = VSTR_PATTERN.matcher(v);
-        if (!m.matches())
-            throw new IllegalArgumentException("Invalid version string: '" + v + "'");
-        
+    {        
         // $VNUM is a dot-separated list of integers of arbitrary length
-        String[] split = m.group("VNUM").split("\\.");
-        int[] version = new int[split.length];
-        for (int i = 0; i < split.length; i++)
-            version[i] = Integer.parseInt(split[i]);
-
-        if (m.group("UNDERSCORE")!=null)
+        String[] split = v.split("[^0-9]");
+        int len = Math.min(split.length,3);
+        int[] version = new int[len];
+        for (int i = 0; i < len; i++)
         {
-            return new JavaVersion(
-                    v,
-                    (version[0]>=9 || version.length==1)?version[0]:version[1],
-                    version[0],
-                    version.length>1?version[1]:0,
-                    version.length>2?version[2]:0,
-                    Integer.parseInt(m.group("UPDATE")),
-                    suffix(version,m.group("PRE"),m.group("OPT"))
-                    );
-        }
-        
-        if (m.group("PLUS")!=null)
-        {
-            return new JavaVersion(
-                    v,
-                    (version[0]>=9 || version.length==1)?version[0]:version[1],
-                    version[0],
-                    version.length>1?version[1]:0,
-                    version.length>2?version[2]:0,
-                    Integer.parseInt(m.group("BUILD")),
-                    suffix(version,m.group("PRE"),m.group("OPT"))
-                    );
+            try
+            {
+                version[i] = Integer.parseInt(split[i]);
+            }
+            catch(Throwable e)
+            {
+                len = i-1;
+                break;
+            }
         }
 
         return new JavaVersion(
                 v,
-                (version[0]>=9 || version.length==1)?version[0]:version[1],
+                (version[0]>=9 || len==1)?version[0]:version[1],
                 version[0],
-                version.length>1?version[1]:0,
-                version.length>2?version[2]:0,
-                0,
-                suffix(version,m.group("PRE"),m.group("OPT"))
-                );
-        
-    }
-
-    private static String suffix(int[] version, String pre, String opt)
-    {
-        StringBuilder buf = new StringBuilder();
-        for (int i=3;i3)
-                buf.append(".");
-            buf.append(version[i]);
-        }
-               
-        if (pre!=null)
-        {
-            if (buf.length()>0)
-                buf.append('-');
-            buf.append(pre);
-        }
-        
-        if (opt!=null)
-        {
-            if (buf.length()>0)
-                buf.append('-');
-            buf.append(opt);
-        }
-        
-        if (buf.length()==0)
-            return null;
-        
-        return buf.toString();
+                len>1?version[1]:0,
+                len>2?version[2]:0);
     }
     
     private final String version;
@@ -131,18 +67,14 @@ public class JavaVersion
     private final int major;
     private final int minor;
     private final int micro;
-    private final int update;
-    private final String suffix;
 
-    private JavaVersion(String version, int platform, int major, int minor, int micro, int update, String suffix)
+    private JavaVersion(String version, int platform, int major, int minor, int micro)
     {
         this.version = version;
         this.platform = platform;
         this.major = major;
         this.minor = minor;
         this.micro = micro;
-        this.update = update;
-        this.suffix = suffix;
     }
 
     /**
@@ -198,9 +130,10 @@ public class JavaVersion
      *
      * @return the update number version
      */
+    @Deprecated
     public int getUpdate()
     {
-        return update;
+        return 0;
     }
 
     /**
@@ -209,9 +142,10 @@ public class JavaVersion
      *
      * @return the remaining string after the version numbers
      */
+    @Deprecated
     public String getSuffix()
     {
-        return suffix;
+        return null;
     }
 
     @Override
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ProcessorUtils.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ProcessorUtils.java
new file mode 100644
index 00000000000..df0d8e3f1a6
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ProcessorUtils.java
@@ -0,0 +1,58 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util;
+
+/**
+ * ProcessorUtils provides access to runtime info about processors, that may be 
+ * overridden by system properties of environment variables.   This can be useful
+ * in virtualised environments where the runtime may miss report the available 
+ * resources.
+ */
+public class ProcessorUtils
+{
+    public static final String AVAILABLE_PROCESSORS = "JETTY_AVAILABLE_PROCESSORS";
+    private static int __availableProcessors = Runtime.getRuntime().availableProcessors();
+
+    static
+    {
+        String avlProcEnv = System.getProperty(AVAILABLE_PROCESSORS,System.getenv(AVAILABLE_PROCESSORS));
+        if (avlProcEnv != null)
+        {
+            try
+            {
+                __availableProcessors = Integer.parseInt( avlProcEnv );
+            }
+            catch ( NumberFormatException e )
+            {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Obtain the number of available processors, from System Property "JETTY_AVAILABLE_PROCESSORS",
+     * or if not set then environment variable "JETTY_AVAILABLE_PROCESSORS" or if not set then
+     * {@link Runtime#availableProcessors()}.
+     * @return the number of processors
+     */
+    public static int availableProcessors()
+    {
+        return __availableProcessors;
+    }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java b/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java
index 363721175cf..455857647a2 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java
@@ -221,7 +221,7 @@ public class UrlEncoded extends MultiMap implements Cloneable
         if (charset==null)
             charset=ENCODING;
 
-        if (charset==StandardCharsets.UTF_8)
+        if (StandardCharsets.UTF_8.equals(charset))
         {
             decodeUtf8To(content,0,content.length(),map);
             return;
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java
index 2c4b40e009f..06ba9101441 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java
@@ -211,7 +211,9 @@ public class StdErrLog extends AbstractLogger
      */
     public StdErrLog(String name, Properties props)
     {
-        if (props!=null && props!=Log.__props)
+        @SuppressWarnings("ReferenceEquality")
+        boolean sameObject = (props!=Log.__props);
+        if (props!=null && sameObject)
             Log.__props.putAll(props);
         _name = name == null?"":name;
         _abbrevname = condensePackageString(this._name);
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java
index 8792924340d..862d3bd7605 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java
@@ -95,7 +95,9 @@ public abstract class Credential implements Serializable
      */
     protected static boolean stringEquals(String known, String unknown)
     {
-        if (known == unknown)
+        @SuppressWarnings("ReferenceEquality")
+        boolean sameObject = (known == unknown);
+        if (sameObject)
             return true;
         if (known == null || unknown == null)
             return false;
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/CounterStatistic.java b/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/CounterStatistic.java
index 22a207aa5ef..933f84de2b3 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/CounterStatistic.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/CounterStatistic.java
@@ -22,51 +22,53 @@ import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.LongAccumulator;
 import java.util.concurrent.atomic.LongAdder;
 
-/* ------------------------------------------------------------ */
-/** Statistics on a counter value.
- * 

- * Keep total, current and maximum values of a counter that - * can be incremented and decremented. The total refers only - * to increments. - * +/** + *

Statistics on a counter value.

+ *

This class keeps the total, current and maximum value of a counter + * that can be incremented and decremented. The total refers only to increments.

*/ public class CounterStatistic { - protected final LongAccumulator _max = new LongAccumulator(Math::max,0L); - protected final AtomicLong _current = new AtomicLong(); - protected final LongAdder _total = new LongAdder(); + private final LongAccumulator _max = new LongAccumulator(Math::max, 0L); + private final AtomicLong _current = new AtomicLong(); + private final LongAdder _total = new LongAdder(); - /* ------------------------------------------------------------ */ + /** + * Resets the max and total to the current value. + */ public void reset() { _total.reset(); _max.reset(); - long current=_current.get(); + long current = _current.get(); _total.add(current); _max.accumulate(current); } - /* ------------------------------------------------------------ */ + /** + * Resets the max, total and current value to the given parameter. + * + * @param value the new current value + */ public void reset(final long value) { _current.set(value); _total.reset(); _max.reset(); - if (value>0) + if (value > 0) { _total.add(value); _max.accumulate(value); } } - /* ------------------------------------------------------------ */ /** - * @param delta the amount to add to the count - * @return the new value + * @param delta the amount to add to the counter + * @return the new counter value */ public long add(final long delta) { - long value=_current.addAndGet(delta); + long value = _current.addAndGet(delta); if (delta > 0) { _total.add(delta); @@ -75,60 +77,56 @@ public class CounterStatistic return value; } - /* ------------------------------------------------------------ */ /** - * increment the value by one - * @return the new value, post increment + * Increments the value by one. + * + * @return the new counter value after the increment */ public long increment() { - long value=_current.incrementAndGet(); + long value = _current.incrementAndGet(); _total.increment(); _max.accumulate(value); return value; } - /* ------------------------------------------------------------ */ /** - * decrement by 1 - * @return the new value, post-decrement + * Decrements the value by one. + * + * @return the new counter value after the decrement */ public long decrement() { return _current.decrementAndGet(); } - /* ------------------------------------------------------------ */ /** - * @return max value + * @return max counter value */ public long getMax() { return _max.get(); } - /* ------------------------------------------------------------ */ /** - * @return current value + * @return current counter value */ public long getCurrent() { return _current.get(); } - /* ------------------------------------------------------------ */ /** - * @return total value + * @return total counter value */ public long getTotal() { return _total.sum(); } - /* ------------------------------------------------------------ */ @Override public String toString() { - return String.format("%s@%x{c=%d,m=%d,t=%d}",this.getClass().getSimpleName(),hashCode(),_current.get(),_max.get(),_total.sum()); + return String.format("%s@%x{c=%d,m=%d,t=%d}", getClass().getSimpleName(), hashCode(), getCurrent(), getMax(), getTotal()); } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/SampleStatistic.java b/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/SampleStatistic.java index 3a5dd2faa71..db8cf39a330 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/SampleStatistic.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/SampleStatistic.java @@ -22,31 +22,26 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.LongAccumulator; import java.util.concurrent.atomic.LongAdder; -import org.eclipse.jetty.util.Atomics; - - /** - * SampledStatistics - *

- * Provides max, total, mean, count, variance, and standard deviation of continuous sequence of samples. - *

- * Calculates estimates of mean, variance, and standard deviation characteristics of a sample using a non synchronized + *

Statistics on a sampled value.

+ *

Provides max, total, mean, count, variance, and standard deviation of continuous sequence of samples.

+ *

Calculates estimates of mean, variance, and standard deviation characteristics of a sample using a non synchronized * approximation of the on-line algorithm presented in Donald Knuth's Art of Computer Programming, Volume 2, - * Semi numerical Algorithms, 3rd edition, page 232, Boston: Addison-Wesley. that cites a 1962 paper by B.P. Welford that - * can be found by following Note on a Method for Calculating Corrected Sums - * of Squares and Products - *

- * This algorithm is also described in Wikipedia at - * Algorithms for calculating variance + * Semi numerical Algorithms, 3rd edition, page 232, Boston: Addison-Wesley. That cites a 1962 paper by B.P. Welford: + * Note on a Method for Calculating Corrected Sums of Squares and Products

+ *

This algorithm is also described in Wikipedia in the section "Online algorithm": + * Algorithms for calculating variance.

*/ public class SampleStatistic { - protected final LongAccumulator _max = new LongAccumulator(Math::max,0L); - protected final AtomicLong _total = new AtomicLong(); - protected final AtomicLong _count = new AtomicLong(); - protected final LongAdder _totalVariance100 = new LongAdder(); + private final LongAccumulator _max = new LongAccumulator(Math::max, 0L); + private final AtomicLong _total = new AtomicLong(); + private final AtomicLong _count = new AtomicLong(); + private final LongAdder _totalVariance100 = new LongAdder(); + /** + * Resets the statistics. + */ public void reset() { _max.reset(); @@ -55,61 +50,89 @@ public class SampleStatistic _totalVariance100.reset(); } - public void set(final long sample) + /** + * Records a sample value. + * + * @param sample the value to record. + */ + public void record(long sample) { long total = _total.addAndGet(sample); long count = _count.incrementAndGet(); - if (count>1) + if (count > 1) { - long mean10 = total*10/count; - long delta10 = sample*10 - mean10; - _totalVariance100.add(delta10*delta10); + long mean10 = total * 10 / count; + long delta10 = sample * 10 - mean10; + _totalVariance100.add(delta10 * delta10); } _max.accumulate(sample); } /** - * @return the max value + * @deprecated use {@link #record(long)} instead + */ + @Deprecated + public void set(long sample) + { + record(sample); + } + + /** + * @return the max value of the recorded samples */ public long getMax() { return _max.get(); } + /** + * @return the sum of all the recorded samples + */ public long getTotal() { return _total.get(); } + /** + * @return the number of samples recorded + */ public long getCount() { return _count.get(); } + /** + * @return the average value of the samples recorded, or zero if there are no samples + */ public double getMean() { - return (double)_total.get()/_count.get(); + long count = getCount(); + return count > 0 ? (double)_total.get() / _count.get() : 0.0D; } + /** + * @return the variance of the samples recorded, or zero if there are less than 2 samples + */ public double getVariance() { - final long variance100 = _totalVariance100.sum(); - final long count = _count.get(); - - return count>1?((double)variance100)/100.0/(count-1):0.0; + long variance100 = _totalVariance100.sum(); + long count = getCount(); + return count > 1 ? variance100 / 100.0D / (count - 1) : 0.0D; } + /** + * @return the standard deviation of the samples recorded + */ public double getStdDev() { return Math.sqrt(getVariance()); } - /* ------------------------------------------------------------ */ @Override public String toString() { - return String.format("%s@%x{c=%d,m=%d,t=%d,v100=%d}",this.getClass().getSimpleName(),hashCode(),_count.get(),_max.get(),_total.get(),_totalVariance100.sum()); + return String.format("%s@%x{count=%d,mean=%d,total=%d,stddev=%f}", getClass().getSimpleName(), hashCode(), getCount(), getMax(), getTotal(), getStdDev()); } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutorThreadPool.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutorThreadPool.java index b37202a8de9..fb95092a2ef 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutorThreadPool.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutorThreadPool.java @@ -28,6 +28,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.component.ContainerLifeCycle; @@ -78,7 +79,7 @@ public class ExecutorThreadPool extends ContainerLifeCycle implements ThreadPool public ExecutorThreadPool(ThreadPoolExecutor executor, int reservedThreads, ThreadGroup group) { - this(executor, Math.min(Runtime.getRuntime().availableProcessors(), executor.getCorePoolSize()), reservedThreads, group); + this( executor, Math.min(ProcessorUtils.availableProcessors(),executor.getCorePoolSize()),reservedThreads,group); } private ExecutorThreadPool(ThreadPoolExecutor executor, int minThreads, int reservedThreads, ThreadGroup group) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/MonitoredQueuedThreadPool.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/MonitoredQueuedThreadPool.java new file mode 100644 index 00000000000..9c120ddc0a8 --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/MonitoredQueuedThreadPool.java @@ -0,0 +1,162 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util.thread; + +import org.eclipse.jetty.util.BlockingArrayQueue; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.annotation.ManagedOperation; +import org.eclipse.jetty.util.statistic.CounterStatistic; +import org.eclipse.jetty.util.statistic.SampleStatistic; + +/** + *

A {@link QueuedThreadPool} subclass that monitors its own activity by recording queue and task statistics.

+ */ +@ManagedObject +public class MonitoredQueuedThreadPool extends QueuedThreadPool +{ + private final CounterStatistic queueStats = new CounterStatistic(); + private final SampleStatistic queueLatencyStats = new SampleStatistic(); + private final SampleStatistic taskLatencyStats = new SampleStatistic(); + private final CounterStatistic threadStats = new CounterStatistic(); + + public MonitoredQueuedThreadPool() + { + this(256); + } + + public MonitoredQueuedThreadPool(int maxThreads) + { + super(maxThreads, maxThreads, 24 * 3600 * 1000, new BlockingArrayQueue<>(maxThreads, 256)); + addBean(queueStats); + addBean(queueLatencyStats); + addBean(taskLatencyStats); + addBean(threadStats); + } + + @Override + public void execute(final Runnable job) + { + queueStats.increment(); + long begin = System.nanoTime(); + super.execute(new Runnable() + { + @Override + public void run() + { + long queueLatency = System.nanoTime() - begin; + queueStats.decrement(); + threadStats.increment(); + queueLatencyStats.set(queueLatency); + long start = System.nanoTime(); + try + { + job.run(); + } + finally + { + long taskLatency = System.nanoTime() - start; + threadStats.decrement(); + taskLatencyStats.set(taskLatency); + } + } + + @Override + public String toString() + { + return job.toString(); + } + }); + } + + /** + * Resets the statistics. + */ + @ManagedOperation(value = "resets the statistics", impact = "ACTION") + public void reset() + { + queueStats.reset(); + queueLatencyStats.reset(); + taskLatencyStats.reset(); + threadStats.reset(0); + } + + /** + * @return the number of tasks executed + */ + @ManagedAttribute("the number of tasks executed") + public long getTasks() + { + return taskLatencyStats.getTotal(); + } + + /** + * @return the maximum number of busy threads + */ + @ManagedAttribute("the maximum number of busy threads") + public int getMaxBusyThreads() + { + return (int)threadStats.getMax(); + } + + /** + * @return the maximum task queue size + */ + @ManagedAttribute("the maximum task queue size") + public int getMaxQueueSize() + { + return (int)queueStats.getMax(); + } + + /** + * @return the average time a task remains in the queue, in nanoseconds + */ + @ManagedAttribute("the average time a task remains in the queue, in nanoseconds") + public long getAverageQueueLatency() + { + return (long)queueLatencyStats.getMean(); + } + + /** + * @return the maximum time a task remains in the queue, in nanoseconds + */ + @ManagedAttribute("the maximum time a task remains in the queue, in nanoseconds") + public long getMaxQueueLatency() + { + return queueLatencyStats.getMax(); + } + + /** + * @return the average task execution time, in nanoseconds + */ + @ManagedAttribute("the average task execution time, in nanoseconds") + public long getAverageTaskLatency() + { + return (long)taskLatencyStats.getMean(); + } + + /** + * @return the maximum task execution time, in nanoseconds + */ + @ManagedAttribute("the maximum task execution time, in nanoseconds") + public long getMaxTaskLatency() + { + return taskLatencyStats.getMax(); + } +} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ReservedThreadExecutor.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ReservedThreadExecutor.java index 718bd0143d1..273aae5c790 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ReservedThreadExecutor.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ReservedThreadExecutor.java @@ -25,6 +25,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Condition; +import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.component.AbstractLifeCycle; @@ -96,7 +97,7 @@ public class ReservedThreadExecutor extends AbstractLifeCycle implements TryExec { if (capacity>=0) return capacity; - int cpus = Runtime.getRuntime().availableProcessors(); + int cpus = ProcessorUtils.availableProcessors(); if (executor instanceof ThreadPool.SizedThreadPool) { int threads = ((ThreadPool.SizedThreadPool)executor).getMaxThreads(); diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ThreadPoolBudget.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ThreadPoolBudget.java index d9725fcb61b..2269effe41f 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ThreadPoolBudget.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ThreadPoolBudget.java @@ -25,6 +25,7 @@ import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; +import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -97,7 +98,7 @@ public class ThreadPoolBudget */ public ThreadPoolBudget(ThreadPool.SizedThreadPool pool) { - this(pool,Math.min(Runtime.getRuntime().availableProcessors(),pool.getMinThreads())); + this(pool,Math.min(ProcessorUtils.availableProcessors(),pool.getMinThreads())); } /** diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/AtomicBiIntegerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/AtomicBiIntegerTest.java new file mode 100644 index 00000000000..edda43df9e4 --- /dev/null +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/AtomicBiIntegerTest.java @@ -0,0 +1,105 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.*; + +import org.junit.Test; + +public class AtomicBiIntegerTest +{ + + @Test + public void testBitOperations() + { + long encoded; + + encoded = AtomicBiInteger.encode(0,0); + assertThat(AtomicBiInteger.getHi(encoded),is(0)); + assertThat(AtomicBiInteger.getLo(encoded),is(0)); + + encoded = AtomicBiInteger.encode(1,2); + assertThat(AtomicBiInteger.getHi(encoded),is(1)); + assertThat(AtomicBiInteger.getLo(encoded),is(2)); + + encoded = AtomicBiInteger.encode(Integer.MAX_VALUE,-1); + assertThat(AtomicBiInteger.getHi(encoded),is(Integer.MAX_VALUE)); + assertThat(AtomicBiInteger.getLo(encoded),is(-1)); + encoded = AtomicBiInteger.encodeLo(encoded,42); + assertThat(AtomicBiInteger.getHi(encoded),is(Integer.MAX_VALUE)); + assertThat(AtomicBiInteger.getLo(encoded),is(42)); + + encoded = AtomicBiInteger.encode(-1,Integer.MAX_VALUE); + assertThat(AtomicBiInteger.getHi(encoded),is(-1)); + assertThat(AtomicBiInteger.getLo(encoded),is(Integer.MAX_VALUE)); + encoded = AtomicBiInteger.encodeHi(encoded,42); + assertThat(AtomicBiInteger.getHi(encoded),is(42)); + assertThat(AtomicBiInteger.getLo(encoded),is(Integer.MAX_VALUE)); + + encoded = AtomicBiInteger.encode(Integer.MIN_VALUE,1); + assertThat(AtomicBiInteger.getHi(encoded),is(Integer.MIN_VALUE)); + assertThat(AtomicBiInteger.getLo(encoded),is(1)); + encoded = AtomicBiInteger.encodeLo(encoded,Integer.MAX_VALUE); + assertThat(AtomicBiInteger.getHi(encoded),is(Integer.MIN_VALUE)); + assertThat(AtomicBiInteger.getLo(encoded),is(Integer.MAX_VALUE)); + + encoded = AtomicBiInteger.encode(1,Integer.MIN_VALUE); + assertThat(AtomicBiInteger.getHi(encoded),is(1)); + assertThat(AtomicBiInteger.getLo(encoded),is(Integer.MIN_VALUE)); + encoded = AtomicBiInteger.encodeHi(encoded,Integer.MAX_VALUE); + assertThat(AtomicBiInteger.getHi(encoded),is(Integer.MAX_VALUE)); + assertThat(AtomicBiInteger.getLo(encoded),is(Integer.MIN_VALUE)); + } + + @Test + public void testSet() + { + AtomicBiInteger abi = new AtomicBiInteger(); + assertThat(abi.getHi(),is(0)); + assertThat(abi.getLo(),is(0)); + + abi.setHi(Integer.MAX_VALUE); + assertThat(abi.getHi(),is(Integer.MAX_VALUE)); + assertThat(abi.getLo(),is(0)); + + abi.setLo(Integer.MIN_VALUE); + assertThat(abi.getHi(),is(Integer.MAX_VALUE)); + assertThat(abi.getLo(),is(Integer.MIN_VALUE)); + } + + @Test + public void testCompareAndSet() + { + AtomicBiInteger abi = new AtomicBiInteger(); + assertThat(abi.getHi(),is(0)); + assertThat(abi.getLo(),is(0)); + + assertFalse(abi.compareAndSetHi(1,42)); + assertTrue(abi.compareAndSetHi(0,42)); + assertThat(abi.getHi(),is(42)); + assertThat(abi.getLo(),is(0)); + + assertFalse(abi.compareAndSetLo(1,-42)); + assertTrue(abi.compareAndSetLo(0,-42)); + assertThat(abi.getHi(),is(42)); + assertThat(abi.getLo(),is(-42)); + } + +} diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/BufferUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/BufferUtilTest.java index ab3ead51d61..5d7492dff93 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/BufferUtilTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/BufferUtilTest.java @@ -297,6 +297,7 @@ public class BufferUtilTest @Test + @SuppressWarnings("ReferenceEquality") public void testEnsureCapacity() throws Exception { ByteBuffer b = BufferUtil.toBuffer("Goodbye Cruel World"); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/DateCacheTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/DateCacheTest.java index d95acb63ef3..80e06435aab 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/DateCacheTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/DateCacheTest.java @@ -40,6 +40,7 @@ public class DateCacheTest /* ------------------------------------------------------------ */ @Test @Slow + @SuppressWarnings("ReferenceEquality") public void testDateCache() throws Exception { //@WAS: Test t = new Test("org.eclipse.jetty.util.DateCache"); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/JavaVersionTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/JavaVersionTest.java index 3c47bf4a353..b02896c454d 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/JavaVersionTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/JavaVersionTest.java @@ -19,7 +19,6 @@ package org.eclipse.jetty.util; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; import org.junit.Test; @@ -29,136 +28,135 @@ import org.junit.Test; */ public class JavaVersionTest { + @Test + public void testAndroid() + { + JavaVersion version = JavaVersion.parse("0.9"); + assertThat(version.toString(),is("0.9")); + assertThat(version.getPlatform(),is(9)); + assertThat(version.getMajor(),is(0)); + assertThat(version.getMinor(),is(9)); + assertThat(version.getMicro(),is(0)); + } + @Test public void test9() { JavaVersion version = JavaVersion.parse("9.0.1"); + assertThat(version.toString(),is("9.0.1")); assertThat(version.getPlatform(),is(9)); assertThat(version.getMajor(),is(9)); assertThat(version.getMinor(),is(0)); assertThat(version.getMicro(),is(1)); - assertThat(version.getUpdate(),is(0)); - assertThat(version.getSuffix(),nullValue()); } @Test public void test9nano() { JavaVersion version = JavaVersion.parse("9.0.1.3"); + assertThat(version.toString(),is("9.0.1.3")); assertThat(version.getPlatform(),is(9)); assertThat(version.getMajor(),is(9)); assertThat(version.getMinor(),is(0)); assertThat(version.getMicro(),is(1)); - assertThat(version.getUpdate(),is(0)); - assertThat(version.getSuffix(),is("3")); } @Test public void test9build() { JavaVersion version = JavaVersion.parse("9.0.1+11"); + assertThat(version.toString(),is("9.0.1+11")); assertThat(version.getPlatform(),is(9)); assertThat(version.getMajor(),is(9)); assertThat(version.getMinor(),is(0)); assertThat(version.getMicro(),is(1)); - assertThat(version.getUpdate(),is(11)); - assertThat(version.getSuffix(),nullValue()); } @Test public void test9all() { JavaVersion version = JavaVersion.parse("9.0.1-ea+11-b01"); + assertThat(version.toString(),is("9.0.1-ea+11-b01")); assertThat(version.getPlatform(),is(9)); assertThat(version.getMajor(),is(9)); assertThat(version.getMinor(),is(0)); assertThat(version.getMicro(),is(1)); - assertThat(version.getUpdate(),is(11)); - assertThat(version.getSuffix(),is("ea-b01")); } @Test public void test9yuck() { JavaVersion version = JavaVersion.parse("9.0.1.2.3-ea+11-b01"); + assertThat(version.toString(),is("9.0.1.2.3-ea+11-b01")); assertThat(version.getPlatform(),is(9)); assertThat(version.getMajor(),is(9)); assertThat(version.getMinor(),is(0)); assertThat(version.getMicro(),is(1)); - assertThat(version.getUpdate(),is(11)); - assertThat(version.getSuffix(),is("2.3-ea-b01")); } @Test public void test10ea() { JavaVersion version = JavaVersion.parse("10-ea"); + assertThat(version.toString(),is("10-ea")); assertThat(version.getPlatform(),is(10)); assertThat(version.getMajor(),is(10)); assertThat(version.getMinor(),is(0)); assertThat(version.getMicro(),is(0)); - assertThat(version.getUpdate(),is(0)); - assertThat(version.getSuffix(),is("ea")); } @Test public void test8() { JavaVersion version = JavaVersion.parse("1.8.0_152"); + assertThat(version.toString(),is("1.8.0_152")); assertThat(version.getPlatform(),is(8)); assertThat(version.getMajor(),is(1)); assertThat(version.getMinor(),is(8)); assertThat(version.getMicro(),is(0)); - assertThat(version.getUpdate(),is(152)); - assertThat(version.getSuffix(),nullValue()); } @Test public void test8ea() { JavaVersion version = JavaVersion.parse("1.8.1_03-ea"); + assertThat(version.toString(),is("1.8.1_03-ea")); assertThat(version.getPlatform(),is(8)); assertThat(version.getMajor(),is(1)); assertThat(version.getMinor(),is(8)); assertThat(version.getMicro(),is(1)); - assertThat(version.getUpdate(),is(3)); - assertThat(version.getSuffix(),is("ea")); } @Test public void test3eaBuild() { JavaVersion version = JavaVersion.parse("1.3.1_05-ea-b01"); + assertThat(version.toString(),is("1.3.1_05-ea-b01")); assertThat(version.getPlatform(),is(3)); assertThat(version.getMajor(),is(1)); assertThat(version.getMinor(),is(3)); assertThat(version.getMicro(),is(1)); - assertThat(version.getUpdate(),is(5)); - assertThat(version.getSuffix(),is("ea-b01")); } @Test public void testUbuntu() { JavaVersion version = JavaVersion.parse("9-Ubuntu+0-9b181-4"); + assertThat(version.toString(),is("9-Ubuntu+0-9b181-4")); assertThat(version.getPlatform(),is(9)); assertThat(version.getMajor(),is(9)); assertThat(version.getMinor(),is(0)); assertThat(version.getMicro(),is(0)); - assertThat(version.getUpdate(),is(0)); - assertThat(version.getSuffix(),is("Ubuntu-9b181-4")); } @Test public void testUbuntu8() { - JavaVersion version = JavaVersion.parse("1.8.0_151-8u151-b12-1~deb9u1-b12"); + JavaVersion version = JavaVersion.parse("1.8.0_151-8u151-b12-1~deb9u1-b12");assertThat(version.toString(),is("1.8.0_151-8u151-b12-1~deb9u1-b12")); assertThat(version.getPlatform(),is(8)); assertThat(version.getMajor(),is(1)); assertThat(version.getMinor(),is(8)); assertThat(version.getMicro(),is(0)); - assertThat(version.getUpdate(),is(151)); - assertThat(version.getSuffix(),is("8u151-b12-1~deb9u1-b12")); } } diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/thread/ThreadMonitorException.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ProcessorUtilsTest.java similarity index 63% rename from jetty-monitor/src/main/java/org/eclipse/jetty/monitor/thread/ThreadMonitorException.java rename to jetty-util/src/test/java/org/eclipse/jetty/util/ProcessorUtilsTest.java index a05ab0690d2..a9b17822be9 100644 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/thread/ThreadMonitorException.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ProcessorUtilsTest.java @@ -16,19 +16,26 @@ // ======================================================================== // -package org.eclipse.jetty.monitor.thread; +package org.eclipse.jetty.util; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; -/* ------------------------------------------------------------ */ /** + * we cannot really add env var in a unit test... so only test we get default value */ -public class ThreadMonitorException extends Exception +public class ProcessorUtilsTest { - private static final long serialVersionUID = -4345223166315716918L; - - public ThreadMonitorException(String message, StackTraceElement[] stackTrace) + @BeforeClass + public static void beforeClass() { - super(message); - setStackTrace(stackTrace); + System.setProperty("JETTY_AVAILABLE_PROCESSORS","42"); + } + + @Test + public void getPropertyValue() + { + Assert.assertEquals(42, ProcessorUtils.availableProcessors()); } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/QueueBenchmarkTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/QueueBenchmarkTest.java index 24952179068..43350bb9f27 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/QueueBenchmarkTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/QueueBenchmarkTest.java @@ -47,7 +47,7 @@ public class QueueBenchmarkTest @Test public void testQueues() throws Exception { - int cores = Runtime.getRuntime().availableProcessors(); + int cores = ProcessorUtils.availableProcessors(); Assume.assumeTrue(cores > 1); final int readers = cores / 2; @@ -66,7 +66,7 @@ public class QueueBenchmarkTest @Test public void testBlockingQueues() throws Exception { - int cores = Runtime.getRuntime().availableProcessors(); + int cores = ProcessorUtils.availableProcessors(); Assume.assumeTrue(cores > 1); final int readers = cores / 2; diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java index dfce5f4b588..273fd429aaa 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java @@ -36,6 +36,7 @@ import static org.junit.Assert.assertTrue; public class StringUtilTest { @Test + @SuppressWarnings("ReferenceEquality") public void testAsciiToLowerCase() { String lc="\u0690bc def 1\u06903"; @@ -88,6 +89,7 @@ public class StringUtilTest } @Test + @SuppressWarnings("ReferenceEquality") public void testReplace() { String s="\u0690bc \u0690bc \u0690bc"; @@ -100,6 +102,7 @@ public class StringUtilTest } @Test + @SuppressWarnings("ReferenceEquality") public void testUnquote() { String uq =" not quoted "; @@ -112,9 +115,10 @@ public class StringUtilTest @Test + @SuppressWarnings("ReferenceEquality") public void testNonNull() { - String nn=""; + String nn="non empty string"; assertTrue(nn==StringUtil.nonNull(nn)); assertEquals("",StringUtil.nonNull(null)); } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/TopologicalSortTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/TopologicalSortTest.java index 05eac6ef68d..3b74d30260c 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/TopologicalSortTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/TopologicalSortTest.java @@ -193,6 +193,7 @@ public class TopologicalSortTest } } + @SuppressWarnings("ReferenceEquality") private int indexOf(String[] list,String s) { for (int i=0;i=0) { while(_threads.isRunning()) @@ -188,7 +190,7 @@ public class ExecutionStrategyTest return null; } }; - + newExecutionStrategy(producer,_threads); _strategy.dispatch(); @@ -205,7 +207,6 @@ public class ExecutionStrategyTest { Thread.sleep(20); q.offer(latch); - _strategy.produce(); } } catch(Exception e) @@ -218,6 +219,7 @@ public class ExecutionStrategyTest if (!latch.await(30,TimeUnit.SECONDS)) { System.err.println(_strategy); + System.err.printf("tasks=%d latch=%d q=%d%n",TASKS,latch.getCount(), q.size()); _threads.dumpStdErr(); Assert.fail(); } diff --git a/jetty-webapp/src/main/config/modules/webapp.mod b/jetty-webapp/src/main/config/modules/webapp.mod index 59f067f8118..cbffca1919c 100644 --- a/jetty-webapp/src/main/config/modules/webapp.mod +++ b/jetty-webapp/src/main/config/modules/webapp.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Adds support for servlet specification webapplication to the server classpath. Without this, only Jetty specific handlers may be deployed. diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/CachingWebAppClassLoader.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/CachingWebAppClassLoader.java index 569068ca5ed..02ce7a33e58 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/CachingWebAppClassLoader.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/CachingWebAppClassLoader.java @@ -64,23 +64,26 @@ public class CachingWebAppClassLoader extends WebAppClassLoader } URL url = _cache.get(name); - - if (name==null) + + if (url == null) { + // Not found in cache, try parent url = super.getResource(name); if (url==null) { + // Still not found, cache the not-found result if (LOG.isDebugEnabled()) LOG.debug("Caching not found resource {}",name); _notFound.add(name); } else { + // Cache the new result _cache.putIfAbsent(name,url); } } - + return url; } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java index 33e9613fc46..4d9c2d173b1 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java @@ -718,9 +718,9 @@ public class ClasspathPattern extends AbstractSet LOG.debug("match {} from {} byName={} byLocation={} in {}",clazz,location,byName,byLocation,this); // Combine the tri-state match of both IncludeExclude Sets - boolean included = byName==Boolean.TRUE || byLocation==Boolean.TRUE + boolean included = Boolean.TRUE.equals(byName) || Boolean.TRUE.equals(byLocation) || (byName==null && !_patterns.hasIncludes() && byLocation==null && !_locations.hasIncludes()); - boolean excluded = byName==Boolean.FALSE || byLocation==Boolean.FALSE; + boolean excluded = Boolean.FALSE.equals(byName) || Boolean.FALSE.equals(byLocation); return included && !excluded; } catch (Exception e) @@ -759,9 +759,9 @@ public class ClasspathPattern extends AbstractSet } // Combine the tri-state match of both IncludeExclude Sets - boolean included = byName==Boolean.TRUE || byLocation==Boolean.TRUE + boolean included = Boolean.TRUE.equals(byName) || Boolean.TRUE.equals(byLocation) || (byName==null && !_patterns.hasIncludes() && byLocation==null && !_locations.hasIncludes()); - boolean excluded = byName==Boolean.FALSE || byLocation==Boolean.FALSE; + boolean excluded = Boolean.FALSE.equals(byName) || Boolean.FALSE.equals(byLocation); return included && !excluded; } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/config/modules/websocket.mod b/jetty-websocket/javax-websocket-server-impl/src/main/config/modules/websocket.mod index 4166982d247..b2a0ecc516c 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/main/config/modules/websocket.mod +++ b/jetty-websocket/javax-websocket-server-impl/src/main/config/modules/websocket.mod @@ -1,3 +1,5 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + [description] Enable websockets for deployed web applications diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java index 03a3b7e52b4..6ff39b3e787 100644 --- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java +++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java @@ -26,6 +26,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; @@ -365,6 +366,15 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont throw new IllegalArgumentException("WebSocket URI scheme only supports [ws] and [wss], not [" + scheme + "]"); } + if ("wss".equals(scheme)) + { + // test for ssl context + if (httpClient.getSslContextFactory() == null) + { + throw new IllegalStateException("HttpClient has no SslContextFactory, wss:// URI's are not supported in this configuration"); + } + } + request.setRequestURI(toUri); request.setLocalEndpoint(websocket); @@ -387,6 +397,17 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont return wsReq.sendAsync(); } + @Override + protected void doStart() throws Exception + { + Objects.requireNonNull(httpClient, "Provided HttpClient is null"); + + super.doStart(); + + if (!httpClient.isRunning()) + throw new IllegalStateException("HttpClient is not running (did you forget to start it?): " + httpClient); + } + @Override protected void doStop() throws Exception { diff --git a/jetty-websocket/websocket-client/src/test/resources/jetty-logging.properties b/jetty-websocket/websocket-client/src/test/resources/jetty-logging.properties index b3767736b29..73c9535473c 100644 --- a/jetty-websocket/websocket-client/src/test/resources/jetty-logging.properties +++ b/jetty-websocket/websocket-client/src/test/resources/jetty-logging.properties @@ -10,6 +10,7 @@ org.eclipse.jetty.LEVEL=WARN # org.eclipse.jetty.websocket.client.ClientCloseTest.LEVEL=DEBUG org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection.LEVEL=DEBUG # org.eclipse.jetty.websocket.common.io.IOState.LEVEL=DEBUG +# org.eclipse.jetty.websocket.common.test.LEVEL=DEBUG # org.eclipse.jetty.websocket.common.Generator.LEVEL=DEBUG org.eclipse.jetty.websocket.common.Parser.LEVEL=DEBUG diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/package-info.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/MoreMatchers.java similarity index 55% rename from jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/package-info.java rename to jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/MoreMatchers.java index e3c71b53fd8..a185e872ee2 100644 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/package-info.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/MoreMatchers.java @@ -16,8 +16,24 @@ // ======================================================================== // -/** - * Jetty Monitor : JMX Integration - */ -package org.eclipse.jetty.monitor.jmx; +package org.eclipse.jetty.websocket.common.test; +import org.eclipse.jetty.toolchain.test.matchers.RegexMatcher; + +public class MoreMatchers +{ + /** + * Create a matcher for {@link String} that matches against a regex pattern. + * + *

+ * Returns success based on {@code java.util.regex.Pattern.matcher(input).matches();} + *

+ * + * @param pattern the {@link java.util.regex.Pattern} syntax pattern to match against. + * @return the Regex Matcher + */ + public static org.hamcrest.Matcher regex(String pattern) + { + return new RegexMatcher(pattern); + } +} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/package-info.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/Timeouts.java similarity index 56% rename from jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/package-info.java rename to jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/Timeouts.java index 257b8f0cee2..d82d964bf08 100644 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/package-info.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/Timeouts.java @@ -16,8 +16,24 @@ // ======================================================================== // -/** - * Jetty Monitor : Intregation with Java Monitor - */ -package org.eclipse.jetty.monitor.integration; +package org.eclipse.jetty.websocket.common.test; +import java.util.concurrent.TimeUnit; + +/** + * A central place for all of the various test timeouts within the websocket testing. + */ +public class Timeouts +{ + // establish a connection timeout + public static final long CONNECT = 2; + public static final TimeUnit CONNECT_UNIT = TimeUnit.SECONDS; + + // poll for an event timeout + public static final long POLL_EVENT = 2; + public static final TimeUnit POLL_EVENT_UNIT = TimeUnit.SECONDS; + + // send a message timeout + public static final long SEND = 2; + public static final TimeUnit SEND_UNIT = TimeUnit.SECONDS; +} diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/package-info.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/WriteCallbackDelegate.java similarity index 56% rename from jetty-monitor/src/main/java/org/eclipse/jetty/monitor/package-info.java rename to jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/WriteCallbackDelegate.java index c4cf607a7ec..0d906c294d1 100644 --- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/package-info.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/WriteCallbackDelegate.java @@ -16,8 +16,31 @@ // ======================================================================== // -/** - * Jetty Monitor : Tool for Monitoring Threads - */ -package org.eclipse.jetty.monitor; +package org.eclipse.jetty.websocket.common.test; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.websocket.api.WriteCallback; + +public class WriteCallbackDelegate implements Callback +{ + private final WriteCallback delegate; + + public WriteCallbackDelegate(WriteCallback delegate) + { + this.delegate = delegate; + } + + @Override + public void succeeded() + { + if (this.delegate != null) + this.delegate.writeSuccess(); + } + + @Override + public void failed(Throwable x) + { + if (this.delegate != null) + this.delegate.writeFailed(x); + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/jsr356/sockets/echo/EchoReturnEndpoint.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/jsr356/sockets/echo/EchoReturnEndpoint.java index 73e8fddb5cb..224416f41e9 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/jsr356/sockets/echo/EchoReturnEndpoint.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/jsr356/sockets/echo/EchoReturnEndpoint.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.websocket.tests.jsr356.sockets.echo; import java.io.IOException; +import java.util.concurrent.LinkedBlockingQueue; import javax.websocket.CloseReason; import javax.websocket.OnMessage; @@ -26,14 +27,12 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; -import org.eclipse.jetty.toolchain.test.EventQueue; - @ServerEndpoint(value = "/echoreturn") public class EchoReturnEndpoint { private Session session = null; public CloseReason close = null; - public EventQueue messageQueue = new EventQueue<>(); + public LinkedBlockingQueue messageQueue = new LinkedBlockingQueue<>(); public void onClose(CloseReason close) { diff --git a/pom.xml b/pom.xml index b69b34af535..bc5745118d0 100644 --- a/pom.xml +++ b/pom.xml @@ -29,6 +29,7 @@ 6.0 1.20 benchmarks + 2.21.0 @@ -440,7 +441,12 @@ org.apache.maven.plugins maven-failsafe-plugin - 2.20.1 + ${surefireVersion} + + + org.apache.maven.plugins + maven-invoker-plugin + 3.0.1 org.apache.maven.plugins @@ -460,7 +466,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.0.0-M1 + 3.0.0 UTF-8 UTF-8 @@ -594,7 +600,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.20 + ${surefireVersion} @{argLine} -Dfile.encoding=UTF-8 -Duser.language=en -Duser.region=US -showversion -Xmx1g -Xms1g -XX:+PrintGCDetails false @@ -1001,12 +1007,57 @@ - + jdk10 10 + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.1-SNAPSHOT + + false + + + + + + + + oss.snapshots + OSS Snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + apache.snapshots + https://repository.apache.org/content/repositories/snapshots + + false + + + true + + + + + + + jdk11 + + 11 + @@ -1018,11 +1069,6 @@ true - - org.apache.maven.plugins - maven-failsafe-plugin - 2.21.0-SNAPSHOT -
@@ -1755,6 +1801,14 @@ IBM -8 + + olamy + Olivier Lamy + oliver.lamy@gmail.com + Webtide, LLC + https://webtide.com + Australia/Brisbane + @@ -1762,6 +1816,9 @@ https://webtide.com + diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java index 2a8e6e10e3f..2b49fc678c6 100644 --- a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java @@ -312,9 +312,7 @@ public abstract class AbstractTest protected String newURI() { if (connector instanceof ServerConnector) - { - return getScheme() + "://localhost:" + ServerConnector.class.cast( connector ).getLocalPort(); - } + return getScheme() + "://localhost:" + ServerConnector.class.cast(connector).getLocalPort(); return getScheme() + "://localhost"; } diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientLoadTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientLoadTest.java index ce97eb30642..615eb8708e1 100644 --- a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientLoadTest.java +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientLoadTest.java @@ -56,6 +56,7 @@ import org.eclipse.jetty.unixsocket.UnixSocketConnector; import org.eclipse.jetty.unixsocket.client.HttpClientTransportOverUnixSockets; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.LeakDetector; +import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Scheduler; @@ -86,7 +87,7 @@ public class HttpClientLoadTest extends AbstractTest unixSocketConnector.setUnixSocket( sockFile.toString() ); return unixSocketConnector; } - int cores = Runtime.getRuntime().availableProcessors(); + int cores = ProcessorUtils.availableProcessors(); ByteBufferPool byteBufferPool = new ArrayByteBufferPool(); byteBufferPool = new LeakTrackingByteBufferPool(byteBufferPool); return new ServerConnector(server, null, null, byteBufferPool, diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/RoundRobinConnectionPoolTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/RoundRobinConnectionPoolTest.java new file mode 100644 index 00000000000..e1c56314d30 --- /dev/null +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/RoundRobinConnectionPoolTest.java @@ -0,0 +1,185 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http.client; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.client.RoundRobinConnectionPool; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.server.Request; +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Test; + +public class RoundRobinConnectionPoolTest extends AbstractTest +{ + public RoundRobinConnectionPoolTest(Transport transport) + { + super(transport); + } + + @Test + public void testRoundRobin() throws Exception + { + AtomicBoolean record = new AtomicBoolean(); + List remotePorts = new ArrayList<>(); + start(new EmptyServerHandler() + { + @Override + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) + { + if (record.get()) + remotePorts.add(request.getRemotePort()); + } + }); + + int maxConnections = 3; + client.getTransport().setConnectionPoolFactory(destination -> new RoundRobinConnectionPool(destination, maxConnections, destination)); + + // Prime the connections, so that they are all opened + // before we actually test the round robin behavior. + for (int i = 0; i < maxConnections; ++i) + { + ContentResponse response = client.newRequest(newURI()) + .timeout(5, TimeUnit.SECONDS) + .send(); + Assert.assertEquals(HttpStatus.OK_200, response.getStatus()); + } + + record.set(true); + int requests = 2 * maxConnections - 1; + for (int i = 0; i < requests; ++i) + { + ContentResponse response = client.newRequest(newURI()) + .timeout(5, TimeUnit.SECONDS) + .send(); + Assert.assertEquals(HttpStatus.OK_200, response.getStatus()); + } + + Assert.assertThat(remotePorts.size(), Matchers.equalTo(requests)); + for (int i = 0; i < requests; ++i) + { + int base = i % maxConnections; + int expected = remotePorts.get(base); + int candidate = remotePorts.get(i); + Assert.assertThat(client.dump() + System.lineSeparator() + remotePorts.toString(), expected, Matchers.equalTo(candidate)); + if (i > 0) + Assert.assertThat(remotePorts.get(i - 1), Matchers.not(Matchers.equalTo(candidate))); + } + } + + @Test + public void testMultiplex() throws Exception + { + int multiplex = 1; + if (transport == Transport.H2C || transport == Transport.H2) + multiplex = 4; + int maxMultiplex = multiplex; + + int maxConnections = 3; + int count = maxConnections * maxMultiplex; + + AtomicBoolean record = new AtomicBoolean(); + List remotePorts = new ArrayList<>(); + AtomicReference requestLatch = new AtomicReference<>(); + CountDownLatch serverLatch = new CountDownLatch(count); + CyclicBarrier barrier = new CyclicBarrier(count + 1); + start(new EmptyServerHandler() + { + @Override + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) + { + try + { + if (record.get()) + { + remotePorts.add(request.getRemotePort()); + requestLatch.get().countDown(); + serverLatch.countDown(); + barrier.await(); + } + } + catch (Exception x) + { + throw new RuntimeException(x); + } + } + }); + + client.getTransport().setConnectionPoolFactory(destination -> new RoundRobinConnectionPool(destination, maxConnections, destination, maxMultiplex)); + + // Prime the connections, so that they are all opened + // before we actually test the round robin behavior. + for (int i = 0; i < maxConnections; ++i) + { + ContentResponse response = client.newRequest(newURI()) + .timeout(5, TimeUnit.SECONDS) + .send(); + Assert.assertEquals(HttpStatus.OK_200, response.getStatus()); + } + + record.set(true); + CountDownLatch clientLatch = new CountDownLatch(count); + AtomicInteger requests = new AtomicInteger(); + for (int i = 0; i < count; ++i) + { + CountDownLatch latch = new CountDownLatch(1); + requestLatch.set(latch); + client.newRequest(newURI()) + .path("/" + i) + .onRequestQueued(request -> requests.incrementAndGet()) + .onRequestBegin(request -> requests.decrementAndGet()) + .timeout(5, TimeUnit.SECONDS) + .send(result -> + { + if (result.getResponse().getStatus() == HttpStatus.OK_200) + clientLatch.countDown(); + }); + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + } + + Assert.assertTrue(serverLatch.await(5, TimeUnit.SECONDS)); + Assert.assertEquals(0, requests.get()); + + barrier.await(); + + Assert.assertTrue(clientLatch.await(5, TimeUnit.SECONDS)); + Assert.assertThat(remotePorts.size(), Matchers.equalTo(count)); + for (int i = 0; i < count; ++i) + { + int base = i % maxConnections; + int expected = remotePorts.get(base); + int candidate = remotePorts.get(i); + Assert.assertThat(client.dump() + System.lineSeparator() + remotePorts.toString(), expected, Matchers.equalTo(candidate)); + if (i > 0) + Assert.assertThat(remotePorts.get(i - 1), Matchers.not(Matchers.equalTo(candidate))); + } + } +} diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateCreateScavengeTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateCreateScavengeTest.java index 48124a96761..872e0e41349 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateCreateScavengeTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateCreateScavengeTest.java @@ -87,6 +87,7 @@ public abstract class AbstractSessionInvalidateCreateScavengeTest extends Abstra } @Test + @SuppressWarnings("ReferenceEquality") public void testSessionScavenge() throws Exception { String contextPath = "/";