Merge remote-tracking branch 'origin/jetty-9.4.x' into jetty-9.4.x-3681-HttpFieldsOptimize
This commit is contained in:
commit
4d60260cd3
|
@ -80,6 +80,31 @@ pipeline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
post {
|
||||||
|
failure {
|
||||||
|
slackNotif()
|
||||||
|
}
|
||||||
|
unstable {
|
||||||
|
slackNotif()
|
||||||
|
}
|
||||||
|
fixed {
|
||||||
|
slackNotif()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def slackNotif() {
|
||||||
|
script {
|
||||||
|
if (env.BRANCH_NAME=='jetty-10.0.x' ||
|
||||||
|
env.BRANCH_NAME=='jetty-9.4.x') {
|
||||||
|
//BUILD_USER = currentBuild.rawBuild.getCause(Cause.UserIdCause).getUserId()
|
||||||
|
// by ${BUILD_USER}
|
||||||
|
COLOR_MAP = ['SUCCESS': 'good', 'FAILURE': 'danger', 'UNSTABLE': 'danger', 'ABORTED': 'danger']
|
||||||
|
slackSend channel: '#jenkins',
|
||||||
|
color: COLOR_MAP[currentBuild.currentResult],
|
||||||
|
message: "*${currentBuild.currentResult}:* Job ${env.JOB_NAME} build ${env.BUILD_NUMBER} - ${env.BUILD_URL}"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -211,7 +211,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>infinispan-remote</artifactId>
|
<artifactId>infinispan-common</artifactId>
|
||||||
<version>9.4.19-SNAPSHOT</version>
|
<version>9.4.19-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -219,11 +219,6 @@
|
||||||
<artifactId>infinispan-remote-query</artifactId>
|
<artifactId>infinispan-remote-query</artifactId>
|
||||||
<version>9.4.19-SNAPSHOT</version>
|
<version>9.4.19-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>infinispan-embedded</artifactId>
|
|
||||||
<version>9.4.19-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>infinispan-embedded-query</artifactId>
|
<artifactId>infinispan-embedded-query</artifactId>
|
||||||
|
|
|
@ -430,6 +430,27 @@
|
||||||
<type>war</type>
|
<type>war</type>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty.tests</groupId>
|
||||||
|
<artifactId>test-jaas-webapp</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>war</type>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty.tests</groupId>
|
||||||
|
<artifactId>test-jndi-webapp</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>war</type>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty.tests</groupId>
|
||||||
|
<artifactId>test-spec-webapp</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>war</type>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-documentation</artifactId>
|
<artifactId>jetty-documentation</artifactId>
|
||||||
|
|
|
@ -18,9 +18,12 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.util.thread.jmh;
|
package org.eclipse.jetty.util.thread.jmh;
|
||||||
|
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||||
import org.eclipse.jetty.util.component.LifeCycle;
|
import org.eclipse.jetty.util.component.LifeCycle;
|
||||||
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
|
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
|
||||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||||
|
@ -42,16 +45,16 @@ import org.openjdk.jmh.runner.options.Options;
|
||||||
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
@Warmup(iterations = 5, time = 10000, timeUnit = TimeUnit.MILLISECONDS)
|
@Warmup(iterations = 8, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
|
||||||
@Measurement(iterations = 3, time = 10000, timeUnit = TimeUnit.MILLISECONDS)
|
@Measurement(iterations = 3, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
|
||||||
public class ThreadPoolBenchmark
|
public class ThreadPoolBenchmark
|
||||||
{
|
{
|
||||||
public enum Type
|
public enum Type
|
||||||
{
|
{
|
||||||
QTP, ETP;
|
QTP, ETP, LQTP, LETP, AQTP, AETP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Param({ "QTP", "ETP"})
|
@Param({ "QTP", "ETP" /*, "LQTP", "LETP", "AQTP", "AETP" */ })
|
||||||
Type type;
|
Type type;
|
||||||
|
|
||||||
@Param({ "200" })
|
@Param({ "200" })
|
||||||
|
@ -65,11 +68,39 @@ public class ThreadPoolBenchmark
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case QTP:
|
case QTP:
|
||||||
pool = new QueuedThreadPool(size,size);
|
{
|
||||||
|
QueuedThreadPool qtp = new QueuedThreadPool(size, size, new BlockingArrayQueue<>(32768, 32768));
|
||||||
|
qtp.setReservedThreads(0);
|
||||||
|
pool = qtp;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ETP:
|
case ETP:
|
||||||
pool = new ExecutorThreadPool(size,size);
|
pool = new ExecutorThreadPool(size, size, new BlockingArrayQueue<>(32768, 32768));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LQTP:
|
||||||
|
{
|
||||||
|
QueuedThreadPool qtp = new QueuedThreadPool(size, size, new LinkedBlockingQueue<>());
|
||||||
|
qtp.setReservedThreads(0);
|
||||||
|
pool = qtp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case LETP:
|
||||||
|
pool = new ExecutorThreadPool(size, size, new LinkedBlockingQueue<>());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AQTP:
|
||||||
|
{
|
||||||
|
QueuedThreadPool qtp = new QueuedThreadPool(size, size, new ArrayBlockingQueue<>(32768));
|
||||||
|
qtp.setReservedThreads(0);
|
||||||
|
pool = qtp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AETP:
|
||||||
|
pool = new ExecutorThreadPool(size, size, new ArrayBlockingQueue<>(32768));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
LifeCycle.start(pool);
|
LifeCycle.start(pool);
|
||||||
|
|
|
@ -14,9 +14,11 @@ As they can be long to run, the tests do not run per default. So to run them you
|
||||||
|
|
||||||
Running single test
|
Running single test
|
||||||
--------------------
|
--------------------
|
||||||
You can run single or set of test as well using the command line argument: ```-Dinvoker.test=jetty-run-mojo-it,jetty-run-war*-it,!jetty-run-distro*```
|
You can run single or set of test as well using the command line argument: ```-Dinvoker.test=it-parent-pom,jetty-run-mojo-it,jetty-run-war*-it,!jetty-run-distro*```
|
||||||
The parameter supports pattern and exclusion with !
|
The parameter supports pattern and exclusion with !
|
||||||
|
|
||||||
|
Due to [files filtering](http://maven.apache.org/plugins/maven-invoker-plugin/examples/filtering.html), ```it-parent-pom``` must be included - otherwise tests will fail during execution.
|
||||||
|
|
||||||
Running Logs
|
Running Logs
|
||||||
--------------------
|
--------------------
|
||||||
The output of each Maven build will be located in /target/it/${project-name}/build.log
|
The output of each Maven build will be located in /target/it/${project-name}/build.log
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>test.jetty-run-mojo-multi-module-single-war-it</groupId>
|
||||||
|
<artifactId>jetty-multi-module-project</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>common</artifactId>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,24 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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 mca.common;
|
||||||
|
|
||||||
|
public class CommonService
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
invoker.goals = test
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>test.jetty-run-mojo-multi-module-single-war-it</groupId>
|
||||||
|
<artifactId>module</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>module-api</artifactId>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,24 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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 mca.module;
|
||||||
|
|
||||||
|
public interface ModuleApi
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>test.jetty-run-mojo-multi-module-single-war-it</groupId>
|
||||||
|
<artifactId>module</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>module-impl</artifactId>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>test.jetty-run-mojo-multi-module-single-war-it</groupId>
|
||||||
|
<artifactId>module-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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 mca.module;
|
||||||
|
|
||||||
|
import mca.common.CommonService;
|
||||||
|
|
||||||
|
public class ModuleImpl implements ModuleApi
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final CommonService cs = new CommonService();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>test.jetty-run-mojo-multi-module-single-war-it</groupId>
|
||||||
|
<artifactId>jetty-multi-module-project</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>module</artifactId>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>module-api</module>
|
||||||
|
<module>module-impl</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>test.jetty-run-mojo-multi-module-single-war-it</groupId>
|
||||||
|
<artifactId>common</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.eclipse.jetty.its</groupId>
|
||||||
|
<artifactId>it-parent-pom</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>test.jetty-run-mojo-multi-module-single-war-it</groupId>
|
||||||
|
<artifactId>jetty-multi-module-project</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<name>Jetty :: multi-module project</name>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>common</module>
|
||||||
|
<module>module</module>
|
||||||
|
<module>webapp-war</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<jetty.version>@project.version@</jetty.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>test.jetty-run-mojo-multi-module-single-war-it</groupId>
|
||||||
|
<artifactId>common</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>test.jetty-run-mojo-multi-module-single-war-it</groupId>
|
||||||
|
<artifactId>module-api</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>test.jetty-run-mojo-multi-module-single-war-it</groupId>
|
||||||
|
<artifactId>module-impl</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
File buildLog = new File( basedir, 'build.log' )
|
||||||
|
assert buildLog.text.contains( 'Started Jetty Server' )
|
||||||
|
|
||||||
|
assert buildLog.text.contains( '(1a) >> javax.servlet.ServletContextListener loaded from jar:' )
|
||||||
|
assert buildLog.text.contains( 'local-repo/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar!/javax/servlet/ServletContextListener.class << (1b)' )
|
||||||
|
|
||||||
|
assert buildLog.text.contains( '(2a) >> mca.common.CommonService loaded from file:' )
|
||||||
|
assert buildLog.text.contains( 'common/target/classes/mca/common/CommonService.class << (2b)' )
|
||||||
|
|
||||||
|
assert buildLog.text.contains( '(3a) >> mca.module.ModuleApi loaded from file:' )
|
||||||
|
assert buildLog.text.contains( 'module/module-api/target/classes/mca/module/ModuleApi.class << (3b)' )
|
||||||
|
|
||||||
|
assert buildLog.text.contains( '(4a) >> mca.module.ModuleImpl loaded from file:' )
|
||||||
|
assert buildLog.text.contains( 'module/module-impl/target/classes/mca/module/ModuleImpl.class << (4b)' )
|
||||||
|
|
||||||
|
assert buildLog.text.contains( '(5a) >> mca.webapp.WebAppServletListener loaded from file:' )
|
||||||
|
assert buildLog.text.contains( 'webapp-war/target/classes/mca/webapp/WebAppServletListener.class << (5b)' )
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>test.jetty-run-mojo-multi-module-single-war-it</groupId>
|
||||||
|
<artifactId>jetty-multi-module-project</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>webapp-war</artifactId>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>test.jetty-run-mojo-multi-module-single-war-it</groupId>
|
||||||
|
<artifactId>module-impl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<jetty.port.file>${project.build.directory}/jetty-run-mojo.txt</jetty.port.file>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>start-jetty</id>
|
||||||
|
<phase>test-compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>start</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<systemProperties>
|
||||||
|
<systemProperty>
|
||||||
|
<name>jetty.port.file</name>
|
||||||
|
<value>${jetty.port.file}</value>
|
||||||
|
</systemProperty>
|
||||||
|
</systemProperties>
|
||||||
|
<nonBlocking>true</nonBlocking>
|
||||||
|
<jettyXml>${basedir}/src/config/jetty.xml</jettyXml>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||||
|
|
||||||
|
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||||
|
<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
|
||||||
|
<Set name="secureScheme">https</Set>
|
||||||
|
<Set name="securePort"><Property name="jetty.secure.port" default="8443" /></Set>
|
||||||
|
<Set name="outputBufferSize">32768</Set>
|
||||||
|
<Set name="requestHeaderSize">8192</Set>
|
||||||
|
<Set name="responseHeaderSize">8192</Set>
|
||||||
|
<Set name="headerCacheSize">4096</Set>
|
||||||
|
</New>
|
||||||
|
|
||||||
|
<Call name="addConnector">
|
||||||
|
<Arg>
|
||||||
|
<New class="org.eclipse.jetty.server.ServerConnector">
|
||||||
|
<Arg name="server"><Ref refid="Server" /></Arg>
|
||||||
|
<Arg name="factories">
|
||||||
|
<Array type="org.eclipse.jetty.server.ConnectionFactory">
|
||||||
|
<Item>
|
||||||
|
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
|
||||||
|
<Arg name="config"><Ref refid="httpConfig" /></Arg>
|
||||||
|
</New>
|
||||||
|
</Item>
|
||||||
|
</Array>
|
||||||
|
</Arg>
|
||||||
|
<Call name="addLifeCycleListener">
|
||||||
|
<Arg>
|
||||||
|
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
|
||||||
|
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||||
|
</New>
|
||||||
|
</Arg>
|
||||||
|
</Call>
|
||||||
|
<Set name="host"><Property name="jetty.host" /></Set>
|
||||||
|
<Set name="port"><Property name="jetty.port" default="0" />0</Set>
|
||||||
|
<Set name="idleTimeout">30000</Set>
|
||||||
|
</New>
|
||||||
|
</Arg>
|
||||||
|
</Call>
|
||||||
|
</Configure>
|
|
@ -0,0 +1,56 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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 mca.webapp;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContextEvent;
|
||||||
|
import javax.servlet.ServletContextListener;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import static java.lang.String.format;
|
||||||
|
|
||||||
|
public class WebAppServletListener implements ServletContextListener
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contextInitialized(ServletContextEvent servletContextEvent)
|
||||||
|
{
|
||||||
|
print("1", "javax.servlet.ServletContextListener");
|
||||||
|
print("2", "mca.common.CommonService");
|
||||||
|
print("3", "mca.module.ModuleApi");
|
||||||
|
print("4", "mca.module.ModuleImpl");
|
||||||
|
print("5", "mca.webapp.WebAppServletListener");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contextDestroyed(ServletContextEvent servletContextEvent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void print(String counter, String className)
|
||||||
|
{
|
||||||
|
String res = className.replaceAll("\\.", "/") + ".class";
|
||||||
|
URL url = Thread.currentThread().getContextClassLoader().getResource(res);
|
||||||
|
System.out.println(
|
||||||
|
format("(%sa) >> %s loaded from %s << (%sb)",
|
||||||
|
counter, className, url, counter)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
|
||||||
|
<!DOCTYPE web-app
|
||||||
|
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
|
||||||
|
"http://java.sun.com/dtd/web-app_2_3.dtd">
|
||||||
|
|
||||||
|
<web-app>
|
||||||
|
<listener>
|
||||||
|
<listener-class>mca.webapp.WebAppServletListener</listener-class>
|
||||||
|
</listener>
|
||||||
|
</web-app>
|
|
@ -21,13 +21,15 @@ package org.eclipse.jetty.maven.plugin;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.maven.artifact.Artifact;
|
import org.apache.maven.artifact.Artifact;
|
||||||
import org.apache.maven.plugin.MojoExecutionException;
|
import org.apache.maven.plugin.MojoExecutionException;
|
||||||
|
@ -38,10 +40,9 @@ import org.apache.maven.plugins.annotations.Mojo;
|
||||||
import org.apache.maven.plugins.annotations.Parameter;
|
import org.apache.maven.plugins.annotations.Parameter;
|
||||||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||||
import org.apache.maven.project.MavenProject;
|
import org.apache.maven.project.MavenProject;
|
||||||
import org.codehaus.plexus.util.StringUtils;
|
import org.eclipse.jetty.maven.plugin.utils.MavenProjectHelper;
|
||||||
import org.eclipse.jetty.util.PathWatcher;
|
import org.eclipse.jetty.util.PathWatcher;
|
||||||
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
|
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||||
import org.eclipse.jetty.webapp.WebAppContext;
|
import org.eclipse.jetty.webapp.WebAppContext;
|
||||||
|
@ -285,8 +286,15 @@ public class JettyRunMojo extends AbstractJettyMojo
|
||||||
if (useTestScope && (testClassesDirectory != null))
|
if (useTestScope && (testClassesDirectory != null))
|
||||||
webApp.setTestClasses (testClassesDirectory);
|
webApp.setTestClasses (testClassesDirectory);
|
||||||
|
|
||||||
webApp.setWebInfLib(getDependencyFiles());
|
MavenProjectHelper mavenProjectHelper = new MavenProjectHelper(project);
|
||||||
|
List<File> webInfLibs = getWebInfLibArtifacts(project).stream()
|
||||||
|
.map(a -> {
|
||||||
|
Path p = mavenProjectHelper.getArtifactPath(a);
|
||||||
|
getLog().debug("Artifact " + a.getId() + " loaded from " + p + " added to WEB-INF/lib");
|
||||||
|
return p.toFile();
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
getLog().debug("WEB-INF/lib initialized (at root)");
|
||||||
|
webApp.setWebInfLib(webInfLibs);
|
||||||
|
|
||||||
//if we have not already set web.xml location, need to set one up
|
//if we have not already set web.xml location, need to set one up
|
||||||
if (webApp.getDescriptor() == null)
|
if (webApp.getDescriptor() == null)
|
||||||
|
@ -519,77 +527,41 @@ public class JettyRunMojo extends AbstractJettyMojo
|
||||||
startScanner();
|
startScanner();
|
||||||
getLog().info("Restart completed at "+new Date().toString());
|
getLog().info("Restart completed at "+new Date().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Collection<Artifact> getWebInfLibArtifacts(Set<Artifact> artifacts)
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private List<File> getDependencyFiles()
|
|
||||||
{
|
{
|
||||||
List<File> dependencyFiles = new ArrayList<>();
|
return artifacts.stream()
|
||||||
for ( Artifact artifact : projectArtifacts)
|
.filter(this::canPutArtifactInWebInfLib)
|
||||||
{
|
.collect(Collectors.toList());
|
||||||
// Include runtime and compile time libraries, and possibly test libs too
|
|
||||||
if(artifact.getType().equals("war"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()))
|
|
||||||
continue; //never add dependencies of scope=provided to the webapp's classpath (see also <useProvidedScope> param)
|
|
||||||
|
|
||||||
if (Artifact.SCOPE_TEST.equals(artifact.getScope()) && !useTestScope)
|
|
||||||
continue; //only add dependencies of scope=test if explicitly required
|
|
||||||
|
|
||||||
MavenProject mavenProject = getProjectReference( artifact, project );
|
|
||||||
|
|
||||||
if (mavenProject != null)
|
|
||||||
{
|
|
||||||
File projectPath = "test-jar".equals( artifact.getType() )?
|
|
||||||
Paths.get( mavenProject.getBuild().getTestOutputDirectory() ).toFile()
|
|
||||||
: Paths.get( mavenProject.getBuild().getOutputDirectory() ).toFile();
|
|
||||||
getLog().debug( "Adding project directory " + projectPath.toString() );
|
|
||||||
dependencyFiles.add( projectPath );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencyFiles.add(artifact.getFile());
|
|
||||||
getLog().debug( "Adding artifact " + artifact.getFile().getName() + " with scope "+artifact.getScope()+" for WEB-INF/lib " );
|
|
||||||
}
|
|
||||||
|
|
||||||
return dependencyFiles;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MavenProject getProjectReference(Artifact artifact, MavenProject project )
|
private Collection<Artifact> getWebInfLibArtifacts(MavenProject mavenProject)
|
||||||
{
|
{
|
||||||
if ( project.getProjectReferences() == null || project.getProjectReferences().isEmpty() )
|
String type = mavenProject.getArtifact().getType();
|
||||||
|
if (!"war".equalsIgnoreCase(type) && !"zip".equalsIgnoreCase(type))
|
||||||
{
|
{
|
||||||
return null;
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
Collection<MavenProject> mavenProjects = project.getProjectReferences().values();
|
return getWebInfLibArtifacts(mavenProject.getArtifacts());
|
||||||
for ( MavenProject mavenProject : mavenProjects )
|
|
||||||
{
|
|
||||||
if ( StringUtils.equals( mavenProject.getId(), artifact.getId() ) )
|
|
||||||
{
|
|
||||||
return mavenProject;
|
|
||||||
}
|
|
||||||
if("test-jar".equals(artifact.getType()))
|
|
||||||
{
|
|
||||||
// getId use type so comparing getId will fail in case of test-jar dependency
|
|
||||||
if ( StringUtils.equals( mavenProject.getGroupId(), artifact.getGroupId() )
|
|
||||||
&& StringUtils.equals( mavenProject.getArtifactId(), artifact.getArtifactId() )
|
|
||||||
&& StringUtils.equals( mavenProject.getVersion(), artifact.getBaseVersion()) )
|
|
||||||
{
|
|
||||||
return mavenProject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean canPutArtifactInWebInfLib(Artifact artifact)
|
||||||
|
{
|
||||||
|
if ("war".equalsIgnoreCase(artifact.getType()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Artifact.SCOPE_TEST.equals(artifact.getScope()) && !useTestScope)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private List<Overlay> getOverlays()
|
private List<Overlay> getOverlays()
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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.maven.plugin.utils;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.apache.maven.artifact.Artifact;
|
||||||
|
import org.apache.maven.project.MavenProject;
|
||||||
|
|
||||||
|
public class MavenProjectHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
private final Map<String, MavenProject> artifactToLocalProjectMap;
|
||||||
|
|
||||||
|
public MavenProjectHelper(MavenProject project)
|
||||||
|
{
|
||||||
|
Set<MavenProject> mavenProjects = resolveProjectDependencies(project, new HashSet<>());
|
||||||
|
artifactToLocalProjectMap = mavenProjects.stream()
|
||||||
|
.collect(Collectors.toMap(MavenProject::getId, Function.identity()));
|
||||||
|
artifactToLocalProjectMap.put(project.getArtifact().getId(), project);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets maven project if referenced in reactor
|
||||||
|
* @param artifact - maven artifact
|
||||||
|
* @return {@link MavenProject} if artifact is referenced in reactor, otherwise null
|
||||||
|
*/
|
||||||
|
public MavenProject getMavenProject(Artifact artifact)
|
||||||
|
{
|
||||||
|
return artifactToLocalProjectMap.get(artifact.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets path to artifact.
|
||||||
|
* If artifact is referenced in reactor, returns path to ${project.build.outputDirectory}.
|
||||||
|
* Otherwise, returns path to location in local m2 repo.
|
||||||
|
*
|
||||||
|
* Cannot return null - maven will complain about unsatisfied dependency during project built.
|
||||||
|
*
|
||||||
|
* @param artifact maven artifact
|
||||||
|
* @return path to artifact
|
||||||
|
*/
|
||||||
|
public Path getArtifactPath(Artifact artifact)
|
||||||
|
{
|
||||||
|
Path path = artifact.getFile().toPath();
|
||||||
|
MavenProject mavenProject = getMavenProject(artifact);
|
||||||
|
if (mavenProject != null)
|
||||||
|
{
|
||||||
|
if ( "test-jar".equals( artifact.getType() )) {
|
||||||
|
path = Paths.get(mavenProject.getBuild().getTestOutputDirectory());
|
||||||
|
} else {
|
||||||
|
path = Paths.get(mavenProject.getBuild().getOutputDirectory());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<MavenProject> resolveProjectDependencies(MavenProject project, Set<MavenProject> visitedProjects)
|
||||||
|
{
|
||||||
|
if (visitedProjects.contains(project))
|
||||||
|
{
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
visitedProjects.add(project);
|
||||||
|
Set<MavenProject> availableProjects = new HashSet<>(project.getProjectReferences().values());
|
||||||
|
for (MavenProject ref : project.getProjectReferences().values())
|
||||||
|
{
|
||||||
|
availableProjects.addAll(resolveProjectDependencies(ref, visitedProjects));
|
||||||
|
}
|
||||||
|
return availableProjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -20,7 +20,6 @@ package org.eclipse.jetty.rewrite.handler;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
@ -32,9 +31,9 @@ import org.eclipse.jetty.util.annotation.Name;
|
||||||
* <p>
|
* <p>
|
||||||
* The replacement string may use $n" to replace the nth capture group.
|
* The replacement string may use $n" to replace the nth capture group.
|
||||||
* <p>
|
* <p>
|
||||||
* All redirects are part of the <a href="http://tools.ietf.org/html/rfc7231#section-6.4"><code>3xx Redirection</code> status code set</a>.
|
* All redirects are part of the <a href="http://tools.ietf.org/html/rfc7231#section-6.4">{@code 3xx Redirection} status code set</a>.
|
||||||
* <p>
|
* <p>
|
||||||
* Defaults to <a href="http://tools.ietf.org/html/rfc7231#section-6.4.3"><code>302 Found</code></a>
|
* Defaults to <a href="http://tools.ietf.org/html/rfc7231#section-6.4.3">{@code 302 Found}</a>
|
||||||
*/
|
*/
|
||||||
public class RedirectRegexRule extends RegexRule
|
public class RedirectRegexRule extends RegexRule
|
||||||
{
|
{
|
||||||
|
@ -43,9 +42,9 @@ public class RedirectRegexRule extends RegexRule
|
||||||
|
|
||||||
public RedirectRegexRule()
|
public RedirectRegexRule()
|
||||||
{
|
{
|
||||||
this(null,null);
|
this(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RedirectRegexRule(@Name("regex") String regex, @Name("location") String location)
|
public RedirectRegexRule(@Name("regex") String regex, @Name("location") String location)
|
||||||
{
|
{
|
||||||
super(regex);
|
super(regex);
|
||||||
|
@ -54,65 +53,63 @@ public class RedirectRegexRule extends RegexRule
|
||||||
setLocation(location);
|
setLocation(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param replacement the URI to redirect to
|
||||||
|
* @deprecated use {@link #setLocation(String)} instead.
|
||||||
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void setReplacement(String replacement)
|
public void setReplacement(String replacement)
|
||||||
{
|
{
|
||||||
_location = replacement;
|
setLocation(replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the redirect location.
|
||||||
|
*
|
||||||
|
* @param location the URI to redirect to
|
||||||
|
*/
|
||||||
public void setLocation(String location)
|
public void setLocation(String location)
|
||||||
{
|
{
|
||||||
_location = location;
|
_location = location;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the redirect status code.
|
* Sets the redirect status code.
|
||||||
*
|
*
|
||||||
* @param statusCode the 3xx redirect status code
|
* @param statusCode the 3xx redirect status code
|
||||||
*/
|
*/
|
||||||
public void setStatusCode(int statusCode)
|
public void setStatusCode(int statusCode)
|
||||||
{
|
{
|
||||||
if ((300 <= statusCode) || (statusCode >= 399))
|
if (statusCode >= 300 && statusCode <= 399)
|
||||||
{
|
|
||||||
_statusCode = statusCode;
|
_statusCode = statusCode;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("Invalid redirect status code " + statusCode + " (must be a value between 300 and 399)");
|
throw new IllegalArgumentException("Invalid redirect status code " + statusCode + " (must be a value between 300 and 399)");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String apply(String target, HttpServletRequest request, HttpServletResponse response, Matcher matcher)
|
protected String apply(String target, HttpServletRequest request, HttpServletResponse response, Matcher matcher) throws IOException
|
||||||
throws IOException
|
|
||||||
{
|
{
|
||||||
target=_location;
|
target = _location;
|
||||||
for (int g=1;g<=matcher.groupCount();g++)
|
for (int g = 1; g <= matcher.groupCount(); g++)
|
||||||
{
|
{
|
||||||
String group = matcher.group(g);
|
String group = matcher.group(g);
|
||||||
target=target.replaceAll("\\$"+g,group);
|
target = target.replaceAll("\\$" + g, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
target = response.encodeRedirectURL(target);
|
target = response.encodeRedirectURL(target);
|
||||||
response.setHeader("Location",RedirectUtil.toRedirectURL(request,target));
|
response.setHeader("Location", RedirectUtil.toRedirectURL(request, target));
|
||||||
response.setStatus(_statusCode);
|
response.setStatus(_statusCode);
|
||||||
response.getOutputStream().flush(); // no output / content
|
response.getOutputStream().flush(); // no output / content
|
||||||
response.getOutputStream().close();
|
response.getOutputStream().close();
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the redirect status code and replacement.
|
* Returns the redirect status code and replacement.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
StringBuilder str = new StringBuilder();
|
return String.format("%s[%d>%s]", super.toString(), _statusCode, _location);
|
||||||
str.append(super.toString());
|
|
||||||
str.append('[').append(_statusCode);
|
|
||||||
str.append('>').append(_location);
|
|
||||||
str.append(']');
|
|
||||||
return str.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,22 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||||
* An AtomicLong with additional methods to treat it as two hi/lo integers.
|
* An AtomicLong with additional methods to treat it as two hi/lo integers.
|
||||||
*/
|
*/
|
||||||
public class AtomicBiInteger extends AtomicLong
|
public class AtomicBiInteger extends AtomicLong
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public AtomicBiInteger()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AtomicBiInteger(long encoded)
|
||||||
|
{
|
||||||
|
super(encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AtomicBiInteger(int hi, int lo)
|
||||||
|
{
|
||||||
|
super(encode(hi, lo));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the hi value
|
* @return the hi value
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,175 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// Copyright (c) 1995-2019 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 as three 21 bit unsigned words.
|
|
||||||
*/
|
|
||||||
public class AtomicTriInteger extends AtomicLong
|
|
||||||
{
|
|
||||||
public static int MAX_VALUE = 0x1FFFFF;
|
|
||||||
public static int MIN_VALUE = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the hi and lo values.
|
|
||||||
*
|
|
||||||
* @param w0 the 0th word
|
|
||||||
* @param w1 the 1st word
|
|
||||||
* @param w2 the 2nd word
|
|
||||||
*/
|
|
||||||
public void set(int w0, int w1, int w2)
|
|
||||||
{
|
|
||||||
set(encode(w0, w1, w2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Atomically sets the word values to the given updated values only if
|
|
||||||
* the current encoded value is as expected.
|
|
||||||
*
|
|
||||||
* @param expectEncoded the expected encoded value
|
|
||||||
* @param w0 the 0th word
|
|
||||||
* @param w1 the 1st word
|
|
||||||
* @param w2 the 2nd word
|
|
||||||
* @return {@code true} if successful.
|
|
||||||
*/
|
|
||||||
public boolean compareAndSet(long expectEncoded, int w0, int w1, int w2)
|
|
||||||
{
|
|
||||||
return compareAndSet(expectEncoded, encode(w0, w1, w2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Atomically adds the given deltas to the current hi and lo values.
|
|
||||||
*
|
|
||||||
* @param delta0 the delta to apply to the 0th word value
|
|
||||||
* @param delta1 the delta to apply to the 1st word value
|
|
||||||
* @param delta2 the delta to apply to the 2nd word value
|
|
||||||
*/
|
|
||||||
public void add(int delta0, int delta1, int delta2)
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
long encoded = get();
|
|
||||||
long update = encode(
|
|
||||||
getWord0(encoded) + delta0,
|
|
||||||
getWord1(encoded) + delta1,
|
|
||||||
getWord2(encoded) + delta2);
|
|
||||||
if (compareAndSet(encoded, update))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets word 0 value
|
|
||||||
*
|
|
||||||
* @return the 16 bit value as an int
|
|
||||||
*/
|
|
||||||
public int getWord0()
|
|
||||||
{
|
|
||||||
return getWord0(get());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets word 1 value
|
|
||||||
*
|
|
||||||
* @return the 16 bit value as an int
|
|
||||||
*/
|
|
||||||
public int getWord1()
|
|
||||||
{
|
|
||||||
return getWord1(get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets word 2 value
|
|
||||||
*
|
|
||||||
* @return the 16 bit value as an int
|
|
||||||
*/
|
|
||||||
public int getWord2()
|
|
||||||
{
|
|
||||||
return getWord2(get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets word 0 value from the given encoded value.
|
|
||||||
*
|
|
||||||
* @param encoded the encoded value
|
|
||||||
* @return the 16 bit value as an int
|
|
||||||
*/
|
|
||||||
public static int getWord0(long encoded)
|
|
||||||
{
|
|
||||||
return (int)((encoded >> 42) & MAX_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets word 0 value from the given encoded value.
|
|
||||||
*
|
|
||||||
* @param encoded the encoded value
|
|
||||||
* @return the 16 bit value as an int
|
|
||||||
*/
|
|
||||||
public static int getWord1(long encoded)
|
|
||||||
{
|
|
||||||
return (int)((encoded >> 21) & MAX_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets word 0 value from the given encoded value.
|
|
||||||
*
|
|
||||||
* @param encoded the encoded value
|
|
||||||
* @return the 16 bit value as an int
|
|
||||||
*/
|
|
||||||
public static int getWord2(long encoded)
|
|
||||||
{
|
|
||||||
return (int)(encoded & MAX_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes 4 16 bit words values into a long.
|
|
||||||
*
|
|
||||||
* @param w0 the 0th word
|
|
||||||
* @param w1 the 1st word
|
|
||||||
* @param w2 the 2nd word
|
|
||||||
* @return the encoded value
|
|
||||||
*/
|
|
||||||
public static long encode(int w0, int w1, int w2)
|
|
||||||
{
|
|
||||||
if (w0 < MIN_VALUE
|
|
||||||
|| w0 > MAX_VALUE
|
|
||||||
|| w1 < MIN_VALUE
|
|
||||||
|| w1 > MAX_VALUE
|
|
||||||
|| w2 < MIN_VALUE
|
|
||||||
|| w2 > MAX_VALUE)
|
|
||||||
throw new IllegalArgumentException(String.format("Words must be %d <= word <= %d: %d, %d, %d", MIN_VALUE, MAX_VALUE, w0, w1, w2));
|
|
||||||
long wl0 = ((long)w0) & MAX_VALUE;
|
|
||||||
long wl1 = ((long)w1) & MAX_VALUE;
|
|
||||||
long wl2 = ((long)w2) & MAX_VALUE;
|
|
||||||
return (wl0 << 42) + (wl1 << 21) + (wl2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
long encoded = get();
|
|
||||||
int w0 = getWord0(encoded);
|
|
||||||
int w1 = getWord1(encoded);
|
|
||||||
int w2 = getWord2(encoded);
|
|
||||||
return String.format("{%d,%d,%d}", w0, w1, w2);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -484,13 +484,56 @@ public class BlockingArrayQueue<E> extends AbstractList<E> implements BlockingQu
|
||||||
@Override
|
@Override
|
||||||
public int drainTo(Collection<? super E> c)
|
public int drainTo(Collection<? super E> c)
|
||||||
{
|
{
|
||||||
throw new UnsupportedOperationException();
|
return drainTo(c, Integer.MAX_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int drainTo(Collection<? super E> c, int maxElements)
|
public int drainTo(Collection<? super E> c, int maxElements)
|
||||||
{
|
{
|
||||||
throw new UnsupportedOperationException();
|
int elements = 0;
|
||||||
|
_tailLock.lock();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_headLock.lock();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
final int head = _indexes[HEAD_OFFSET];
|
||||||
|
final int tail = _indexes[TAIL_OFFSET];
|
||||||
|
final int capacity = _elements.length;
|
||||||
|
|
||||||
|
int i = head;
|
||||||
|
while (i!=tail && elements<maxElements)
|
||||||
|
{
|
||||||
|
elements++;
|
||||||
|
c.add((E)_elements[i]);
|
||||||
|
++i;
|
||||||
|
if (i == capacity)
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i==tail)
|
||||||
|
{
|
||||||
|
_indexes[HEAD_OFFSET] = 0;
|
||||||
|
_indexes[TAIL_OFFSET] = 0;
|
||||||
|
_size.set(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_indexes[HEAD_OFFSET] = i;
|
||||||
|
_size.addAndGet(-elements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_headLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_tailLock.unlock();
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
||||||
|
@ -505,7 +548,6 @@ public class BlockingArrayQueue<E> extends AbstractList<E> implements BlockingQu
|
||||||
_tailLock.lock();
|
_tailLock.lock();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
_headLock.lock();
|
_headLock.lock();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -63,7 +64,12 @@ public class ExecutorThreadPool extends ContainerLifeCycle implements ThreadPool
|
||||||
|
|
||||||
public ExecutorThreadPool(int maxThreads, int minThreads)
|
public ExecutorThreadPool(int maxThreads, int minThreads)
|
||||||
{
|
{
|
||||||
this(new ThreadPoolExecutor(maxThreads, maxThreads, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>()), minThreads, -1, null);
|
this(maxThreads, minThreads, new LinkedBlockingQueue<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecutorThreadPool(int maxThreads, int minThreads, BlockingQueue<Runnable> queue)
|
||||||
|
{
|
||||||
|
this(new ThreadPoolExecutor(maxThreads, maxThreads, 60, TimeUnit.SECONDS, queue), minThreads, -1, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExecutorThreadPool(ThreadPoolExecutor executor)
|
public ExecutorThreadPool(ThreadPoolExecutor executor)
|
||||||
|
|
514
jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java
Executable file → Normal file
514
jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java
Executable file → Normal file
|
@ -29,7 +29,7 @@ import java.util.concurrent.RejectedExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.AtomicTriInteger;
|
import org.eclipse.jetty.util.AtomicBiInteger;
|
||||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||||
|
@ -48,15 +48,16 @@ import org.eclipse.jetty.util.thread.ThreadPool.SizedThreadPool;
|
||||||
public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadPool, Dumpable, TryExecutor
|
public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadPool, Dumpable, TryExecutor
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(QueuedThreadPool.class);
|
private static final Logger LOG = Log.getLogger(QueuedThreadPool.class);
|
||||||
|
private static Runnable NOOP = () -> {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes thread counts: <dl>
|
* Encodes thread counts:
|
||||||
* <dt>Word0</dt><dd>Total thread count (including starting and idle)</dd>
|
* <dl>
|
||||||
* <dt>Word1</dt><dd>Starting threads</dd>
|
* <dt>Hi</dt><dd>Total thread count or Integer.MIN_VALUE if stopping</dd>
|
||||||
* <dt>Word2</dt><dd>Idle threads</dd>
|
* <dt>Lo</dt><dd>Net idle threads == idle threads - job queue size</dd>
|
||||||
* </dl>
|
* </dl>
|
||||||
*/
|
*/
|
||||||
private final AtomicTriInteger _counts = new AtomicTriInteger();
|
private final AtomicBiInteger _counts = new AtomicBiInteger(Integer.MIN_VALUE, 0);
|
||||||
private final AtomicLong _lastShrink = new AtomicLong();
|
private final AtomicLong _lastShrink = new AtomicLong();
|
||||||
private final Set<Thread> _threads = ConcurrentHashMap.newKeySet();
|
private final Set<Thread> _threads = ConcurrentHashMap.newKeySet();
|
||||||
private final Object _joinLock = new Object();
|
private final Object _joinLock = new Object();
|
||||||
|
@ -84,12 +85,17 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
this(maxThreads, Math.min(8, maxThreads));
|
this(maxThreads, Math.min(8, maxThreads));
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueuedThreadPool(@Name("maxThreads") int maxThreads, @Name("minThreads") int minThreads)
|
public QueuedThreadPool(@Name("maxThreads") int maxThreads, @Name("minThreads") int minThreads)
|
||||||
{
|
{
|
||||||
this(maxThreads, minThreads, 60000);
|
this(maxThreads, minThreads, 60000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueuedThreadPool(@Name("maxThreads") int maxThreads, @Name("minThreads") int minThreads, @Name("idleTimeout")int idleTimeout)
|
public QueuedThreadPool(@Name("maxThreads") int maxThreads, @Name("minThreads") int minThreads, @Name("queue") BlockingQueue<Runnable> queue)
|
||||||
|
{
|
||||||
|
this(maxThreads, minThreads, 60000, -1, queue, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueuedThreadPool(@Name("maxThreads") int maxThreads, @Name("minThreads") int minThreads, @Name("idleTimeout") int idleTimeout)
|
||||||
{
|
{
|
||||||
this(maxThreads, minThreads, idleTimeout, null);
|
this(maxThreads, minThreads, idleTimeout, null);
|
||||||
}
|
}
|
||||||
|
@ -103,26 +109,24 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
{
|
{
|
||||||
this(maxThreads, minThreads, idleTimeout, -1, queue, threadGroup);
|
this(maxThreads, minThreads, idleTimeout, -1, queue, threadGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueuedThreadPool(@Name("maxThreads") int maxThreads, @Name("minThreads") int minThreads, @Name("idleTimeout") int idleTimeout, @Name("reservedThreads") int reservedThreads, @Name("queue") BlockingQueue<Runnable> queue, @Name("threadGroup") ThreadGroup threadGroup)
|
public QueuedThreadPool(@Name("maxThreads") int maxThreads, @Name("minThreads") int minThreads, @Name("idleTimeout") int idleTimeout, @Name("reservedThreads") int reservedThreads, @Name("queue") BlockingQueue<Runnable> queue, @Name("threadGroup") ThreadGroup threadGroup)
|
||||||
{
|
{
|
||||||
if (maxThreads < minThreads) {
|
if (maxThreads < minThreads)
|
||||||
throw new IllegalArgumentException("max threads ("+maxThreads+") less than min threads ("
|
throw new IllegalArgumentException("max threads (" + maxThreads + ") less than min threads ("
|
||||||
+minThreads+")");
|
+ minThreads + ")");
|
||||||
}
|
|
||||||
|
|
||||||
setMinThreads(minThreads);
|
setMinThreads(minThreads);
|
||||||
setMaxThreads(maxThreads);
|
setMaxThreads(maxThreads);
|
||||||
setIdleTimeout(idleTimeout);
|
setIdleTimeout(idleTimeout);
|
||||||
setStopTimeout(5000);
|
setStopTimeout(5000);
|
||||||
setReservedThreads(reservedThreads);
|
setReservedThreads(reservedThreads);
|
||||||
if (queue==null)
|
if (queue == null)
|
||||||
{
|
{
|
||||||
int capacity=Math.max(_minThreads, 8);
|
int capacity = Math.max(_minThreads, 8) * 1024;
|
||||||
queue=new BlockingArrayQueue<>(capacity, capacity);
|
queue = new BlockingArrayQueue<>(capacity, capacity);
|
||||||
}
|
}
|
||||||
_jobs=queue;
|
_jobs = queue;
|
||||||
_threadGroup=threadGroup;
|
_threadGroup = threadGroup;
|
||||||
setThreadPoolBudget(new ThreadPoolBudget(this));
|
setThreadPoolBudget(new ThreadPoolBudget(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +138,7 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
|
|
||||||
public void setThreadPoolBudget(ThreadPoolBudget budget)
|
public void setThreadPoolBudget(ThreadPoolBudget budget)
|
||||||
{
|
{
|
||||||
if (budget!=null && budget.getSizedThreadPool()!=this)
|
if (budget != null && budget.getSizedThreadPool() != this)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
_budget = budget;
|
_budget = budget;
|
||||||
}
|
}
|
||||||
|
@ -142,21 +146,21 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
@Override
|
@Override
|
||||||
protected void doStart() throws Exception
|
protected void doStart() throws Exception
|
||||||
{
|
{
|
||||||
if (_reservedThreads==0)
|
if (_reservedThreads == 0)
|
||||||
{
|
{
|
||||||
_tryExecutor = NO_TRY;
|
_tryExecutor = NO_TRY;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ReservedThreadExecutor reserved = new ReservedThreadExecutor(this,_reservedThreads);
|
ReservedThreadExecutor reserved = new ReservedThreadExecutor(this, _reservedThreads);
|
||||||
reserved.setIdleTimeout(_idleTimeout,TimeUnit.MILLISECONDS);
|
reserved.setIdleTimeout(_idleTimeout, TimeUnit.MILLISECONDS);
|
||||||
_tryExecutor = reserved;
|
_tryExecutor = reserved;
|
||||||
}
|
}
|
||||||
addBean(_tryExecutor);
|
addBean(_tryExecutor);
|
||||||
|
|
||||||
super.doStart();
|
|
||||||
|
|
||||||
_counts.set(0,0,0); // threads, starting, idle
|
super.doStart();
|
||||||
|
// The threads count set to MIN_VALUE is used to signal to Runners that the pool is stopped.
|
||||||
|
_counts.set(0, 0); // threads, idle
|
||||||
ensureThreads();
|
ensureThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,54 +172,59 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
|
|
||||||
removeBean(_tryExecutor);
|
removeBean(_tryExecutor);
|
||||||
_tryExecutor = TryExecutor.NO_TRY;
|
_tryExecutor = TryExecutor.NO_TRY;
|
||||||
|
|
||||||
super.doStop();
|
super.doStop();
|
||||||
|
|
||||||
|
// Signal the Runner threads that we are stopping
|
||||||
|
int threads = _counts.getAndSetHi(Integer.MIN_VALUE);
|
||||||
|
|
||||||
|
// If stop timeout try to gracefully stop
|
||||||
long timeout = getStopTimeout();
|
long timeout = getStopTimeout();
|
||||||
BlockingQueue<Runnable> jobs = getQueue();
|
BlockingQueue<Runnable> jobs = getQueue();
|
||||||
|
if (timeout > 0)
|
||||||
// If no stop timeout, clear job queue
|
|
||||||
if (timeout <= 0)
|
|
||||||
jobs.clear();
|
|
||||||
|
|
||||||
// Fill job Q with noop jobs to wakeup idle
|
|
||||||
Runnable noop = () -> {};
|
|
||||||
for (int i = getThreads(); i-- > 0; )
|
|
||||||
jobs.offer(noop);
|
|
||||||
|
|
||||||
// try to let jobs complete naturally for half our stop time
|
|
||||||
joinThreads(System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeout) / 2);
|
|
||||||
|
|
||||||
// If we still have threads running, get a bit more aggressive
|
|
||||||
|
|
||||||
// interrupt remaining threads
|
|
||||||
for (Thread thread : _threads)
|
|
||||||
{
|
{
|
||||||
if (LOG.isDebugEnabled())
|
// Fill the job queue with noop jobs to wakeup idle threads.
|
||||||
LOG.debug("Interrupting {}", thread);
|
for (int i = 0; i < threads; ++i)
|
||||||
thread.interrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait again for the other half of our stop time
|
|
||||||
joinThreads(System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeout) / 2);
|
|
||||||
|
|
||||||
Thread.yield();
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
{
|
|
||||||
for (Thread unstopped : _threads)
|
|
||||||
{
|
{
|
||||||
StringBuilder dmp = new StringBuilder();
|
jobs.offer(NOOP);
|
||||||
for (StackTraceElement element : unstopped.getStackTrace())
|
}
|
||||||
{
|
|
||||||
dmp.append(System.lineSeparator()).append("\tat ").append(element);
|
// try to let jobs complete naturally for half our stop time
|
||||||
}
|
joinThreads(System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeout) / 2);
|
||||||
LOG.warn("Couldn't stop {}{}", unstopped, dmp.toString());
|
|
||||||
|
// If we still have threads running, get a bit more aggressive
|
||||||
|
|
||||||
|
// interrupt remaining threads
|
||||||
|
for (Thread thread : _threads)
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Interrupting {}", thread);
|
||||||
|
thread.interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait again for the other half of our stop time
|
||||||
|
joinThreads(System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeout) / 2);
|
||||||
|
|
||||||
|
Thread.yield();
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
{
|
||||||
|
for (Thread unstopped : _threads)
|
||||||
|
{
|
||||||
|
StringBuilder dmp = new StringBuilder();
|
||||||
|
for (StackTraceElement element : unstopped.getStackTrace())
|
||||||
|
{
|
||||||
|
dmp.append(System.lineSeparator()).append("\tat ").append(element);
|
||||||
|
}
|
||||||
|
LOG.warn("Couldn't stop {}{}", unstopped, dmp.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (Thread unstopped : _threads)
|
||||||
|
{
|
||||||
|
LOG.warn("{} Couldn't stop {}", this, unstopped);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (Thread unstopped : _threads)
|
|
||||||
LOG.warn("{} Couldn't stop {}",this,unstopped);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close any un-executed jobs
|
// Close any un-executed jobs
|
||||||
|
@ -233,11 +242,11 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
LOG.warn(t);
|
LOG.warn(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (job != noop)
|
else if (job != NOOP)
|
||||||
LOG.warn("Stopped without executing or closing {}", job);
|
LOG.warn("Stopped without executing or closing {}", job);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_budget!=null)
|
if (_budget != null)
|
||||||
_budget.reset();
|
_budget.reset();
|
||||||
|
|
||||||
synchronized (_joinLock)
|
synchronized (_joinLock)
|
||||||
|
@ -259,7 +268,7 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thread Pool should use Daemon Threading.
|
* Thread Pool should use Daemon Threading.
|
||||||
*
|
*
|
||||||
* @param daemon true to enable delegation
|
* @param daemon true to enable delegation
|
||||||
* @see Thread#setDaemon(boolean)
|
* @see Thread#setDaemon(boolean)
|
||||||
|
@ -291,9 +300,7 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
@Override
|
@Override
|
||||||
public void setMaxThreads(int maxThreads)
|
public void setMaxThreads(int maxThreads)
|
||||||
{
|
{
|
||||||
if (maxThreads<AtomicTriInteger.MIN_VALUE || maxThreads>AtomicTriInteger.MAX_VALUE)
|
if (_budget != null)
|
||||||
throw new IllegalArgumentException("maxThreads="+maxThreads);
|
|
||||||
if (_budget!=null)
|
|
||||||
_budget.check(maxThreads);
|
_budget.check(maxThreads);
|
||||||
_maxThreads = maxThreads;
|
_maxThreads = maxThreads;
|
||||||
if (_minThreads > _maxThreads)
|
if (_minThreads > _maxThreads)
|
||||||
|
@ -317,11 +324,11 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
if (isStarted())
|
if (isStarted())
|
||||||
ensureThreads();
|
ensureThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the number of reserved threads.
|
* Set the number of reserved threads.
|
||||||
*
|
*
|
||||||
* @param reservedThreads number of reserved threads or -1 for heuristically determined
|
* @param reservedThreads number of reserved threads or -1 for heuristically determined
|
||||||
* @see #getReservedThreads
|
* @see #getReservedThreads
|
||||||
*/
|
*/
|
||||||
public void setReservedThreads(int reservedThreads)
|
public void setReservedThreads(int reservedThreads)
|
||||||
|
@ -426,10 +433,10 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
{
|
{
|
||||||
return _priority;
|
return _priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the size of the job queue.
|
* Get the size of the job queue.
|
||||||
*
|
*
|
||||||
* @return Number of jobs queued waiting for a thread
|
* @return Number of jobs queued waiting for a thread
|
||||||
*/
|
*/
|
||||||
@ManagedAttribute("size of the job queue")
|
@ManagedAttribute("size of the job queue")
|
||||||
|
@ -458,7 +465,7 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
{
|
{
|
||||||
_detailedDump = detailedDump;
|
_detailedDump = detailedDump;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ManagedAttribute("threshold at which the pool is low on threads")
|
@ManagedAttribute("threshold at which the pool is low on threads")
|
||||||
public int getLowThreadsThreshold()
|
public int getLowThreadsThreshold()
|
||||||
{
|
{
|
||||||
|
@ -473,22 +480,55 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
@Override
|
@Override
|
||||||
public void execute(Runnable job)
|
public void execute(Runnable job)
|
||||||
{
|
{
|
||||||
if (!isRunning() || !_jobs.offer(job))
|
// Determine if we need to start a thread, use and idle thread or just queue this job
|
||||||
|
boolean startThread;
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
LOG.warn("{} rejected {}", this, job);
|
// Get the atomic counts
|
||||||
|
long counts = _counts.get();
|
||||||
|
|
||||||
|
// Get the number of threads started (might not yet be running)
|
||||||
|
int threads = AtomicBiInteger.getHi(counts);
|
||||||
|
if (threads == Integer.MIN_VALUE)
|
||||||
|
throw new RejectedExecutionException(job.toString());
|
||||||
|
|
||||||
|
// Get the number of truly idle threads. This count is reduced by the
|
||||||
|
// job queue size so that any threads that are idle but are about to take
|
||||||
|
// a job from the queue are not counted.
|
||||||
|
int idle = AtomicBiInteger.getLo(counts);
|
||||||
|
|
||||||
|
// Start a thread if we have insufficient idle threads to meet demand
|
||||||
|
// and we are not at max threads.
|
||||||
|
startThread = (idle <= 0 && threads < _maxThreads);
|
||||||
|
|
||||||
|
// The job will be run by an idle thread when available
|
||||||
|
if (!_counts.compareAndSet(counts, threads + (startThread ? 1 : 0), idle - 1))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_jobs.offer(job))
|
||||||
|
{
|
||||||
|
// reverse our changes to _counts.
|
||||||
|
if (addCounts(startThread ? -1 : 0, 1))
|
||||||
|
LOG.warn("{} rejected {}", this, job);
|
||||||
throw new RejectedExecutionException(job.toString());
|
throw new RejectedExecutionException(job.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("queue {}",job);
|
LOG.debug("queue {} startThread={}", job, startThread);
|
||||||
// Make sure there is at least one thread executing the job.
|
|
||||||
ensureThreads();
|
// Start a thread if one was needed
|
||||||
|
if (startThread)
|
||||||
|
startThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean tryExecute(Runnable task)
|
public boolean tryExecute(Runnable task)
|
||||||
{
|
{
|
||||||
TryExecutor tryExecutor = _tryExecutor;
|
TryExecutor tryExecutor = _tryExecutor;
|
||||||
return tryExecutor!=null && tryExecutor.tryExecute(task);
|
return tryExecutor != null && tryExecutor.tryExecute(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -500,11 +540,15 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
synchronized (_joinLock)
|
synchronized (_joinLock)
|
||||||
{
|
{
|
||||||
while (isRunning())
|
while (isRunning())
|
||||||
|
{
|
||||||
_joinLock.wait();
|
_joinLock.wait();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (isStopping())
|
while (isStopping())
|
||||||
|
{
|
||||||
Thread.sleep(1);
|
Thread.sleep(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -514,7 +558,8 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
@ManagedAttribute("number of threads in the pool")
|
@ManagedAttribute("number of threads in the pool")
|
||||||
public int getThreads()
|
public int getThreads()
|
||||||
{
|
{
|
||||||
return _counts.getWord0();
|
int threads = _counts.getHi();
|
||||||
|
return Math.max(0, threads);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -524,7 +569,8 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
@ManagedAttribute("number of idle threads in the pool")
|
@ManagedAttribute("number of idle threads in the pool")
|
||||||
public int getIdleThreads()
|
public int getIdleThreads()
|
||||||
{
|
{
|
||||||
return _counts.getWord2();
|
int idle = _counts.getLo();
|
||||||
|
return Math.max(0, idle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -536,7 +582,7 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
int reserved = _tryExecutor instanceof ReservedThreadExecutor ? ((ReservedThreadExecutor)_tryExecutor).getAvailable() : 0;
|
int reserved = _tryExecutor instanceof ReservedThreadExecutor ? ((ReservedThreadExecutor)_tryExecutor).getAvailable() : 0;
|
||||||
return getThreads() - getIdleThreads() - reserved;
|
return getThreads() - getIdleThreads() - reserved;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns whether this thread pool is low on threads.</p>
|
* <p>Returns whether this thread pool is low on threads.</p>
|
||||||
* <p>The current formula is:</p>
|
* <p>The current formula is:</p>
|
||||||
|
@ -556,43 +602,63 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
|
|
||||||
private void ensureThreads()
|
private void ensureThreads()
|
||||||
{
|
{
|
||||||
while (isRunning())
|
while (true)
|
||||||
{
|
{
|
||||||
long counts = _counts.get();
|
long counts = _counts.get();
|
||||||
int threads = AtomicTriInteger.getWord0(counts);
|
int threads = AtomicBiInteger.getHi(counts);
|
||||||
int starting = AtomicTriInteger.getWord1(counts);
|
if (threads == Integer.MIN_VALUE)
|
||||||
int idle = AtomicTriInteger.getWord2(counts);
|
break;
|
||||||
int queue = getQueueSize();
|
|
||||||
|
|
||||||
if (threads >= _maxThreads)
|
// If we have less than min threads
|
||||||
break;
|
// OR insufficient idle threads to meet demand
|
||||||
if (threads >= _minThreads && (starting + idle) >= queue)
|
int idle = AtomicBiInteger.getLo(counts);
|
||||||
break;
|
if (threads < _minThreads || (idle < 0 && threads < _maxThreads))
|
||||||
if (!_counts.compareAndSet(counts, threads + 1, starting + 1, idle))
|
{
|
||||||
|
// Then try to start a thread.
|
||||||
|
if (_counts.compareAndSet(counts, threads + 1, idle))
|
||||||
|
startThread();
|
||||||
|
// Otherwise continue to check state again.
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
boolean started = false;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("Starting thread {}",this);
|
|
||||||
|
|
||||||
Thread thread = newThread(_runnable);
|
|
||||||
thread.setDaemon(isDaemon());
|
|
||||||
thread.setPriority(getThreadsPriority());
|
|
||||||
thread.setName(_name + "-" + thread.getId());
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("Starting {}", thread);
|
|
||||||
_threads.add(thread);
|
|
||||||
_lastShrink.set(System.nanoTime());
|
|
||||||
thread.start();
|
|
||||||
started = true;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (!started)
|
|
||||||
_counts.add(-1,-1,0); // threads, starting, idle
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void startThread()
|
||||||
|
{
|
||||||
|
boolean started = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread thread = newThread(_runnable);
|
||||||
|
thread.setDaemon(isDaemon());
|
||||||
|
thread.setPriority(getThreadsPriority());
|
||||||
|
thread.setName(_name + "-" + thread.getId());
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Starting {}", thread);
|
||||||
|
_threads.add(thread);
|
||||||
|
_lastShrink.set(System.nanoTime());
|
||||||
|
thread.start();
|
||||||
|
started = true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (!started)
|
||||||
|
addCounts(-1, 0); // threads, idle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean addCounts(int deltaThreads, int deltaIdle)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
long encoded = _counts.get();
|
||||||
|
int threads = AtomicBiInteger.getHi(encoded);
|
||||||
|
int idle = AtomicBiInteger.getLo(encoded);
|
||||||
|
if (threads == Integer.MIN_VALUE) // This is a marker that the pool is stopped.
|
||||||
|
return false;
|
||||||
|
long update = AtomicBiInteger.encode(threads + deltaThreads, idle + deltaIdle);
|
||||||
|
if (_counts.compareAndSet(encoded, update))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,19 +687,19 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
knownMethod = "IDLE ";
|
knownMethod = "IDLE ";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("reservedWait".equals(t.getMethodName()) && t.getClassName().endsWith("ReservedThread"))
|
if ("reservedWait".equals(t.getMethodName()) && t.getClassName().endsWith("ReservedThread"))
|
||||||
{
|
{
|
||||||
knownMethod = "RESERVED ";
|
knownMethod = "RESERVED ";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("select".equals(t.getMethodName()) && t.getClassName().endsWith("SelectorProducer"))
|
if ("select".equals(t.getMethodName()) && t.getClassName().endsWith("SelectorProducer"))
|
||||||
{
|
{
|
||||||
knownMethod = "SELECTING ";
|
knownMethod = "SELECTING ";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("accept".equals(t.getMethodName()) && t.getClassName().contains("ServerConnector"))
|
if ("accept".equals(t.getMethodName()) && t.getClassName().contains("ServerConnector"))
|
||||||
{
|
{
|
||||||
knownMethod = "ACCEPTING ";
|
knownMethod = "ACCEPTING ";
|
||||||
|
@ -664,8 +730,8 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int p=thread.getPriority();
|
int p = thread.getPriority();
|
||||||
threads.add(thread.getId() + " " + thread.getName() + " " + known + thread.getState() + " @ " + (trace.length > 0 ? trace[0] : "???") + (p==Thread.NORM_PRIORITY?"":(" prio="+p)));
|
threads.add(thread.getId() + " " + thread.getName() + " " + known + thread.getState() + " @ " + (trace.length > 0 ? trace[0] : "???") + (p == Thread.NORM_PRIORITY ? "" : (" prio=" + p)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -684,12 +750,11 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
long count = _counts.get();
|
long count = _counts.get();
|
||||||
int threads = AtomicTriInteger.getWord0(count);
|
int threads = Math.max(0, AtomicBiInteger.getHi(count));
|
||||||
int starting = AtomicTriInteger.getWord1(count);
|
int idle = Math.max(0, AtomicBiInteger.getLo(count));
|
||||||
int idle = AtomicTriInteger.getWord2(count);
|
|
||||||
int queue = getQueueSize();
|
int queue = getQueueSize();
|
||||||
|
|
||||||
return String.format("%s[%s]@%x{%s,%d<=%d<=%d,s=%d,i=%d,r=%d,q=%d}[%s]",
|
return String.format("%s[%s]@%x{%s,%d<=%d<=%d,i=%d,r=%d,q=%d}[%s]",
|
||||||
getClass().getSimpleName(),
|
getClass().getSimpleName(),
|
||||||
_name,
|
_name,
|
||||||
hashCode(),
|
hashCode(),
|
||||||
|
@ -697,7 +762,6 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
getMinThreads(),
|
getMinThreads(),
|
||||||
threads,
|
threads,
|
||||||
getMaxThreads(),
|
getMaxThreads(),
|
||||||
starting,
|
|
||||||
idle,
|
idle,
|
||||||
getReservedThreads(),
|
getReservedThreads(),
|
||||||
queue,
|
queue,
|
||||||
|
@ -768,7 +832,9 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
buf.append(thread.getId()).append(" ").append(thread.getName()).append(" ");
|
buf.append(thread.getId()).append(" ").append(thread.getName()).append(" ");
|
||||||
buf.append(thread.getState()).append(":").append(System.lineSeparator());
|
buf.append(thread.getState()).append(":").append(System.lineSeparator());
|
||||||
for (StackTraceElement element : thread.getStackTrace())
|
for (StackTraceElement element : thread.getStackTrace())
|
||||||
|
{
|
||||||
buf.append(" at ").append(element.toString()).append(System.lineSeparator());
|
buf.append(" at ").append(element.toString()).append(System.lineSeparator());
|
||||||
|
}
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -777,102 +843,110 @@ public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadP
|
||||||
|
|
||||||
private class Runner implements Runnable
|
private class Runner implements Runnable
|
||||||
{
|
{
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
boolean idle = false;
|
|
||||||
Runnable job = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
job = _jobs.poll();
|
|
||||||
idle = job==null;
|
|
||||||
_counts.add(0,-1,idle?1:0); // threads, starting, idle
|
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("Runner started with {} for {}", job, QueuedThreadPool.this);
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (job == null)
|
|
||||||
{
|
|
||||||
if (!idle)
|
|
||||||
{
|
|
||||||
idle = true;
|
|
||||||
_counts.add(0,0,1); // threads, starting, idle
|
|
||||||
}
|
|
||||||
|
|
||||||
long idleTimeout = getIdleTimeout();
|
|
||||||
job = idleJobPoll(idleTimeout);
|
|
||||||
|
|
||||||
// maybe we should shrink?
|
|
||||||
if (job == null && getThreads() > _minThreads && idleTimeout > 0)
|
|
||||||
{
|
|
||||||
long last = _lastShrink.get();
|
|
||||||
long now = System.nanoTime();
|
|
||||||
if (last == 0 || (now - last) > TimeUnit.MILLISECONDS.toNanos(idleTimeout))
|
|
||||||
{
|
|
||||||
if (_lastShrink.compareAndSet(last, now))
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("shrinking {}", QueuedThreadPool.this);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// run job
|
|
||||||
if (job != null)
|
|
||||||
{
|
|
||||||
if (idle)
|
|
||||||
{
|
|
||||||
idle = false;
|
|
||||||
_counts.add(0,0,-1); // threads, starting, idle
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("run {} in {}", job, QueuedThreadPool.this);
|
|
||||||
runJob(job);
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("ran {} in {}", job, QueuedThreadPool.this);
|
|
||||||
|
|
||||||
// Clear interrupted status
|
|
||||||
Thread.interrupted();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isRunning())
|
|
||||||
break;
|
|
||||||
|
|
||||||
job = _jobs.poll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (InterruptedException e)
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("interrupted {} in {}", job, QueuedThreadPool.this);
|
|
||||||
LOG.ignore(e);
|
|
||||||
}
|
|
||||||
catch (Throwable e)
|
|
||||||
{
|
|
||||||
LOG.warn(String.format("Unexpected thread death: %s in %s", job, QueuedThreadPool.this), e);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_counts.add(-1,0,idle?-1:0); // threads, starting, idle
|
|
||||||
removeThread(Thread.currentThread());
|
|
||||||
ensureThreads();
|
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("Runner exited for {}", QueuedThreadPool.this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Runnable idleJobPoll(long idleTimeout) throws InterruptedException
|
private Runnable idleJobPoll(long idleTimeout) throws InterruptedException
|
||||||
{
|
{
|
||||||
if (idleTimeout <= 0)
|
if (idleTimeout <= 0)
|
||||||
return _jobs.take();
|
return _jobs.take();
|
||||||
return _jobs.poll(idleTimeout, TimeUnit.MILLISECONDS);
|
return _jobs.poll(idleTimeout, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Runner started for {}", QueuedThreadPool.this);
|
||||||
|
|
||||||
|
Runnable job = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// All threads start idle (not yet taken a job)
|
||||||
|
if (!addCounts(0, 1))
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// If we had a job, signal that we are idle again
|
||||||
|
if (job != null)
|
||||||
|
{
|
||||||
|
if (!addCounts(0, 1))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// else check we are still running
|
||||||
|
else if (_counts.getHi() == Integer.MIN_VALUE)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Look for an immediately available job
|
||||||
|
job = _jobs.poll();
|
||||||
|
if (job == null)
|
||||||
|
{
|
||||||
|
// Wait for a job
|
||||||
|
long idleTimeout = getIdleTimeout();
|
||||||
|
job = idleJobPoll(idleTimeout);
|
||||||
|
|
||||||
|
// If still no job?
|
||||||
|
if (job == null)
|
||||||
|
{
|
||||||
|
// maybe we should shrink
|
||||||
|
if (getThreads() > _minThreads && idleTimeout > 0)
|
||||||
|
{
|
||||||
|
long last = _lastShrink.get();
|
||||||
|
long now = System.nanoTime();
|
||||||
|
if (last == 0 || (now - last) > TimeUnit.MILLISECONDS.toNanos(idleTimeout))
|
||||||
|
{
|
||||||
|
if (_lastShrink.compareAndSet(last, now))
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("shrinking {}", QueuedThreadPool.this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// continue to try again
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// run job
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("run {} in {}", job, QueuedThreadPool.this);
|
||||||
|
runJob(job);
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("ran {} in {}", job, QueuedThreadPool.this);
|
||||||
|
|
||||||
|
// Clear any interrupted status
|
||||||
|
Thread.interrupted();
|
||||||
|
}
|
||||||
|
catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("interrupted {} in {}", job, QueuedThreadPool.this);
|
||||||
|
LOG.ignore(e);
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
LOG.warn(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Thread thread = Thread.currentThread();
|
||||||
|
removeThread(thread);
|
||||||
|
|
||||||
|
// Decrement the total thread count and the idle count if we had no job
|
||||||
|
addCounts(-1, job == null ? -1 : 0);
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("{} exited for {}", thread, QueuedThreadPool.this);
|
||||||
|
|
||||||
|
// There is a chance that we shrunk just as a job was queued for us, so
|
||||||
|
// check again if we have sufficient threads to meet demand
|
||||||
|
ensureThreads();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
27
jetty-util/src/main/java/org/eclipse/jetty/util/thread/ScheduledExecutorScheduler.java
Executable file → Normal file
27
jetty-util/src/main/java/org/eclipse/jetty/util/thread/ScheduledExecutorScheduler.java
Executable file → Normal file
|
@ -21,7 +21,6 @@ package org.eclipse.jetty.util.thread;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import java.util.concurrent.ThreadFactory;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||||
|
@ -47,13 +46,13 @@ public class ScheduledExecutorScheduler extends AbstractLifeCycle implements Sch
|
||||||
public ScheduledExecutorScheduler()
|
public ScheduledExecutorScheduler()
|
||||||
{
|
{
|
||||||
this(null, false);
|
this(null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScheduledExecutorScheduler(String name, boolean daemon)
|
public ScheduledExecutorScheduler(String name, boolean daemon)
|
||||||
{
|
{
|
||||||
this (name,daemon, Thread.currentThread().getContextClassLoader());
|
this(name, daemon, Thread.currentThread().getContextClassLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScheduledExecutorScheduler(String name, boolean daemon, ClassLoader threadFactoryClassLoader)
|
public ScheduledExecutorScheduler(String name, boolean daemon, ClassLoader threadFactoryClassLoader)
|
||||||
{
|
{
|
||||||
this(name, daemon, threadFactoryClassLoader, null);
|
this(name, daemon, threadFactoryClassLoader, null);
|
||||||
|
@ -70,16 +69,12 @@ public class ScheduledExecutorScheduler extends AbstractLifeCycle implements Sch
|
||||||
@Override
|
@Override
|
||||||
protected void doStart() throws Exception
|
protected void doStart() throws Exception
|
||||||
{
|
{
|
||||||
scheduler = new ScheduledThreadPoolExecutor(1, new ThreadFactory()
|
scheduler = new ScheduledThreadPoolExecutor(1, r ->
|
||||||
{
|
{
|
||||||
@Override
|
Thread thread = ScheduledExecutorScheduler.this.thread = new Thread(threadGroup, r, name);
|
||||||
public Thread newThread(Runnable r)
|
thread.setDaemon(daemon);
|
||||||
{
|
thread.setContextClassLoader(classloader);
|
||||||
Thread thread = ScheduledExecutorScheduler.this.thread = new Thread(threadGroup, r, name);
|
return thread;
|
||||||
thread.setDaemon(daemon);
|
|
||||||
thread.setContextClassLoader(classloader);
|
|
||||||
return thread;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
scheduler.setRemoveOnCancelPolicy(true);
|
scheduler.setRemoveOnCancelPolicy(true);
|
||||||
super.doStart();
|
super.doStart();
|
||||||
|
@ -97,8 +92,8 @@ public class ScheduledExecutorScheduler extends AbstractLifeCycle implements Sch
|
||||||
public Task schedule(Runnable task, long delay, TimeUnit unit)
|
public Task schedule(Runnable task, long delay, TimeUnit unit)
|
||||||
{
|
{
|
||||||
ScheduledThreadPoolExecutor s = scheduler;
|
ScheduledThreadPoolExecutor s = scheduler;
|
||||||
if (s==null)
|
if (s == null)
|
||||||
return ()->false;
|
return () -> false;
|
||||||
ScheduledFuture<?> result = s.schedule(task, delay, unit);
|
ScheduledFuture<?> result = s.schedule(task, delay, unit);
|
||||||
return new ScheduledFutureTask(result);
|
return new ScheduledFutureTask(result);
|
||||||
}
|
}
|
||||||
|
@ -116,7 +111,7 @@ public class ScheduledExecutorScheduler extends AbstractLifeCycle implements Sch
|
||||||
if (thread == null)
|
if (thread == null)
|
||||||
Dumpable.dumpObject(out, this);
|
Dumpable.dumpObject(out, this);
|
||||||
else
|
else
|
||||||
Dumpable.dumpObjects(out,indent,this, (Object[])thread.getStackTrace());
|
Dumpable.dumpObjects(out, indent, this, (Object[])thread.getStackTrace());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ScheduledFutureTask implements Task
|
private static class ScheduledFutureTask implements Task
|
||||||
|
|
|
@ -1,103 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// Copyright (c) 1995-2019 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 org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.eclipse.jetty.util.AtomicTriInteger.MAX_VALUE;
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
public class AtomicTriIntegerTest
|
|
||||||
{
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testBitOperations()
|
|
||||||
{
|
|
||||||
long encoded;
|
|
||||||
|
|
||||||
encoded = AtomicTriInteger.encode(0,0,0);
|
|
||||||
assertThat(AtomicTriInteger.getWord0(encoded),is(0));
|
|
||||||
assertThat(AtomicTriInteger.getWord1(encoded),is(0));
|
|
||||||
assertThat(AtomicTriInteger.getWord2(encoded),is(0));
|
|
||||||
|
|
||||||
encoded = AtomicTriInteger.encode(1,2,3);
|
|
||||||
assertThat(AtomicTriInteger.getWord0(encoded),is(1));
|
|
||||||
assertThat(AtomicTriInteger.getWord1(encoded),is(2));
|
|
||||||
assertThat(AtomicTriInteger.getWord2(encoded),is(3));
|
|
||||||
|
|
||||||
encoded = AtomicTriInteger.encode(MAX_VALUE, MAX_VALUE, MAX_VALUE);
|
|
||||||
assertThat(AtomicTriInteger.getWord0(encoded),is(MAX_VALUE));
|
|
||||||
assertThat(AtomicTriInteger.getWord1(encoded),is(MAX_VALUE));
|
|
||||||
assertThat(AtomicTriInteger.getWord2(encoded),is(MAX_VALUE));
|
|
||||||
|
|
||||||
assertThrows(IllegalArgumentException.class,()-> AtomicTriInteger.encode(-1, MAX_VALUE, MAX_VALUE));
|
|
||||||
assertThrows(IllegalArgumentException.class,()-> AtomicTriInteger.encode(MAX_VALUE, -1, MAX_VALUE));
|
|
||||||
assertThrows(IllegalArgumentException.class,()-> AtomicTriInteger.encode(MAX_VALUE, MAX_VALUE, -1));
|
|
||||||
assertThrows(IllegalArgumentException.class,()-> AtomicTriInteger.encode(MAX_VALUE+1, MAX_VALUE, MAX_VALUE));
|
|
||||||
assertThrows(IllegalArgumentException.class,()-> AtomicTriInteger.encode(MAX_VALUE, MAX_VALUE+1, MAX_VALUE));
|
|
||||||
assertThrows(IllegalArgumentException.class,()-> AtomicTriInteger.encode(MAX_VALUE, MAX_VALUE, MAX_VALUE+1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetGet()
|
|
||||||
{
|
|
||||||
AtomicTriInteger ati = new AtomicTriInteger();
|
|
||||||
ati.set(1,2,3);
|
|
||||||
assertThat(ati.getWord0(),is(1));
|
|
||||||
assertThat(ati.getWord1(),is(2));
|
|
||||||
assertThat(ati.getWord2(),is(3));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCompareAndSet()
|
|
||||||
{
|
|
||||||
AtomicTriInteger ati = new AtomicTriInteger();
|
|
||||||
ati.set(1,2,3);
|
|
||||||
long value = ati.get();
|
|
||||||
|
|
||||||
ati.set(2,3,4);
|
|
||||||
assertFalse(ati.compareAndSet(value,5,6,7));
|
|
||||||
assertThat(ati.getWord0(),is(2));
|
|
||||||
assertThat(ati.getWord1(),is(3));
|
|
||||||
assertThat(ati.getWord2(),is(4));
|
|
||||||
|
|
||||||
value = ati.get();
|
|
||||||
assertTrue(ati.compareAndSet(value,6,7,8));
|
|
||||||
assertThat(ati.getWord0(),is(6));
|
|
||||||
assertThat(ati.getWord1(),is(7));
|
|
||||||
assertThat(ati.getWord2(),is(8));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAdd()
|
|
||||||
{
|
|
||||||
AtomicTriInteger ati = new AtomicTriInteger();
|
|
||||||
ati.set(1,2,3);
|
|
||||||
ati.add(-1,-2,4);
|
|
||||||
assertThat(ati.getWord0(),is(0));
|
|
||||||
assertThat(ati.getWord1(),is(0));
|
|
||||||
assertThat(ati.getWord2(),is(7));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -18,12 +18,9 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.util;
|
package org.eclipse.jetty.util;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import java.util.ArrayList;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
@ -31,10 +28,16 @@ import java.util.concurrent.CyclicBarrier;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
|
import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
public class BlockingArrayQueueTest
|
public class BlockingArrayQueueTest
|
||||||
{
|
{
|
||||||
@Test
|
@Test
|
||||||
|
@ -494,4 +497,28 @@ public class BlockingArrayQueueTest
|
||||||
assertTrue(iterator.hasNext());
|
assertTrue(iterator.hasNext());
|
||||||
assertFalse(iterator.hasPrevious());
|
assertFalse(iterator.hasPrevious());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDrainTo() throws Exception
|
||||||
|
{
|
||||||
|
BlockingArrayQueue<String> queue = new BlockingArrayQueue<>();
|
||||||
|
queue.add("one");
|
||||||
|
queue.add("two");
|
||||||
|
queue.add("three");
|
||||||
|
queue.add("four");
|
||||||
|
queue.add("five");
|
||||||
|
queue.add("six");
|
||||||
|
|
||||||
|
List<String> to = new ArrayList<>();
|
||||||
|
queue.drainTo(to,3);
|
||||||
|
assertThat(to, Matchers.contains("one", "two", "three"));
|
||||||
|
assertThat(queue.size(),Matchers.is(3));
|
||||||
|
assertThat(queue, Matchers.contains("four", "five", "six"));
|
||||||
|
|
||||||
|
queue.drainTo(to);
|
||||||
|
assertThat(to, Matchers.contains("one", "two", "three", "four", "five", "six"));
|
||||||
|
assertThat(queue.size(),Matchers.is(0));
|
||||||
|
assertThat(queue, Matchers.empty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,6 +181,7 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
||||||
RunningJob job4=new RunningJob("JOB4");
|
RunningJob job4=new RunningJob("JOB4");
|
||||||
tp.execute(job4);
|
tp.execute(job4);
|
||||||
assertFalse(job4._run.await(1,TimeUnit.SECONDS));
|
assertFalse(job4._run.await(1,TimeUnit.SECONDS));
|
||||||
|
assertThat(tp.getThreads(),is(4));
|
||||||
|
|
||||||
// finish job 0
|
// finish job 0
|
||||||
job0._stopping.countDown();
|
job0._stopping.countDown();
|
||||||
|
@ -214,19 +215,21 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
||||||
duration = System.nanoTime() - duration;
|
duration = System.nanoTime() - duration;
|
||||||
assertThat(TimeUnit.NANOSECONDS.toMillis(duration), Matchers.greaterThan(tp.getIdleTimeout()/2L));
|
assertThat(TimeUnit.NANOSECONDS.toMillis(duration), Matchers.greaterThan(tp.getIdleTimeout()/2L));
|
||||||
assertThat(TimeUnit.NANOSECONDS.toMillis(duration), Matchers.lessThan(tp.getIdleTimeout()*2L));
|
assertThat(TimeUnit.NANOSECONDS.toMillis(duration), Matchers.lessThan(tp.getIdleTimeout()*2L));
|
||||||
|
|
||||||
|
tp.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testThreadPoolFailingJobs() throws Exception
|
public void testThreadPoolFailingJobs() throws Exception
|
||||||
{
|
{
|
||||||
|
QueuedThreadPool tp= new QueuedThreadPool();
|
||||||
|
tp.setMinThreads(2);
|
||||||
|
tp.setMaxThreads(4);
|
||||||
|
tp.setIdleTimeout(900);
|
||||||
|
tp.setThreadsPriority(Thread.NORM_PRIORITY-1);
|
||||||
|
|
||||||
try (StacklessLogging stackless = new StacklessLogging(QueuedThreadPool.class))
|
try (StacklessLogging stackless = new StacklessLogging(QueuedThreadPool.class))
|
||||||
{
|
{
|
||||||
QueuedThreadPool tp= new QueuedThreadPool();
|
|
||||||
tp.setMinThreads(2);
|
|
||||||
tp.setMaxThreads(4);
|
|
||||||
tp.setIdleTimeout(900);
|
|
||||||
tp.setThreadsPriority(Thread.NORM_PRIORITY-1);
|
|
||||||
|
|
||||||
tp.start();
|
tp.start();
|
||||||
|
|
||||||
// min threads started
|
// min threads started
|
||||||
|
@ -297,8 +300,10 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
||||||
assertTrue(job4._stopped.await(10,TimeUnit.SECONDS));
|
assertTrue(job4._stopped.await(10,TimeUnit.SECONDS));
|
||||||
|
|
||||||
waitForIdle(tp,2);
|
waitForIdle(tp,2);
|
||||||
assertThat(tp.getThreads(),is(2));
|
waitForThreads(tp,2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tp.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -340,6 +345,8 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
||||||
RunningJob job4 = new RunningJob();
|
RunningJob job4 = new RunningJob();
|
||||||
tp.execute(job4);
|
tp.execute(job4);
|
||||||
assertTrue(job4._run.await(5, TimeUnit.SECONDS));
|
assertTrue(job4._run.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
tp.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -364,7 +371,7 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
||||||
tp.execute(job0);
|
tp.execute(job0);
|
||||||
tp.execute(job1);
|
tp.execute(job1);
|
||||||
|
|
||||||
// Add a more jobs (which should not be run)
|
// Add more jobs (which should not be run)
|
||||||
RunningJob job2=new RunningJob();
|
RunningJob job2=new RunningJob();
|
||||||
CloseableJob job3=new CloseableJob();
|
CloseableJob job3=new CloseableJob();
|
||||||
RunningJob job4=new RunningJob();
|
RunningJob job4=new RunningJob();
|
||||||
|
@ -391,6 +398,8 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
||||||
// Verify ClosableJobs have not been run but have been closed
|
// Verify ClosableJobs have not been run but have been closed
|
||||||
assertThat(job4._run.await(200, TimeUnit.MILLISECONDS), is(false));
|
assertThat(job4._run.await(200, TimeUnit.MILLISECONDS), is(false));
|
||||||
assertThat(job3._closed.await(200, TimeUnit.MILLISECONDS), is(true));
|
assertThat(job3._closed.await(200, TimeUnit.MILLISECONDS), is(true));
|
||||||
|
|
||||||
|
tp.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -437,6 +446,7 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
||||||
}
|
}
|
||||||
waitForThreads(tp,2);
|
waitForThreads(tp,2);
|
||||||
waitForIdle(tp,2);
|
waitForIdle(tp,2);
|
||||||
|
tp.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -484,6 +494,27 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
||||||
assertEquals(idle, tp.getIdleThreads());
|
assertEquals(idle, tp.getIdleThreads());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void waitForReserved(QueuedThreadPool tp, int reserved)
|
||||||
|
{
|
||||||
|
long now=TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
|
||||||
|
long start=now;
|
||||||
|
ReservedThreadExecutor reservedThreadExecutor = tp.getBean(ReservedThreadExecutor.class);
|
||||||
|
while (reservedThreadExecutor.getAvailable()!=reserved && (now-start)<10000)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(50);
|
||||||
|
}
|
||||||
|
catch(InterruptedException ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
now=TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
|
||||||
|
}
|
||||||
|
assertEquals(reserved, reservedThreadExecutor.getAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void waitForThreads(QueuedThreadPool tp, int threads)
|
private void waitForThreads(QueuedThreadPool tp, int threads)
|
||||||
{
|
{
|
||||||
long now=TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
|
long now=TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
|
||||||
|
@ -520,6 +551,7 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
assertThat(tp.getThreads(),greaterThanOrEqualTo(5));
|
assertThat(tp.getThreads(),greaterThanOrEqualTo(5));
|
||||||
}
|
}
|
||||||
|
tp.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -548,24 +580,26 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
||||||
public void testDump() throws Exception
|
public void testDump() throws Exception
|
||||||
{
|
{
|
||||||
QueuedThreadPool pool = new QueuedThreadPool(4, 3);
|
QueuedThreadPool pool = new QueuedThreadPool(4, 3);
|
||||||
|
pool.setIdleTimeout(10000);
|
||||||
|
|
||||||
String dump = pool.dump();
|
String dump = pool.dump();
|
||||||
// TODO use hamcrest 2.0 regex matcher
|
// TODO use hamcrest 2.0 regex matcher
|
||||||
assertThat(dump,containsString("STOPPED"));
|
assertThat(dump,containsString("STOPPED"));
|
||||||
assertThat(dump,containsString(",3<=0<=4,s=0,i=0,r=-1,q=0"));
|
assertThat(dump,containsString(",3<=0<=4,i=0,r=-1,q=0"));
|
||||||
assertThat(dump,containsString("[NO_TRY]"));
|
assertThat(dump,containsString("[NO_TRY]"));
|
||||||
|
|
||||||
pool.setReservedThreads(2);
|
pool.setReservedThreads(2);
|
||||||
dump = pool.dump();
|
dump = pool.dump();
|
||||||
assertThat(dump,containsString("STOPPED"));
|
assertThat(dump,containsString("STOPPED"));
|
||||||
assertThat(dump,containsString(",3<=0<=4,s=0,i=0,r=2,q=0"));
|
assertThat(dump,containsString(",3<=0<=4,i=0,r=2,q=0"));
|
||||||
assertThat(dump,containsString("[NO_TRY]"));
|
assertThat(dump,containsString("[NO_TRY]"));
|
||||||
|
|
||||||
pool.start();
|
pool.start();
|
||||||
waitForIdle(pool,3);
|
waitForIdle(pool,3);
|
||||||
|
Thread.sleep(250); // TODO need to give time for threads to read idle poll after setting idle
|
||||||
dump = pool.dump();
|
dump = pool.dump();
|
||||||
assertThat(count(dump," - STARTED"),is(2));
|
assertThat(count(dump," - STARTED"),is(2));
|
||||||
assertThat(dump,containsString(",3<=3<=4,s=0,i=3,r=2,q=0"));
|
assertThat(dump,containsString(",3<=3<=4,i=3,r=2,q=0"));
|
||||||
assertThat(dump,containsString("[ReservedThreadExecutor@"));
|
assertThat(dump,containsString("[ReservedThreadExecutor@"));
|
||||||
assertThat(count(dump," IDLE "),is(3));
|
assertThat(count(dump," IDLE "),is(3));
|
||||||
assertThat(count(dump," RESERVED "),is(0));
|
assertThat(count(dump," RESERVED "),is(0));
|
||||||
|
@ -585,10 +619,10 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
started.await();
|
started.await();
|
||||||
|
Thread.sleep(250); // TODO need to give time for threads to read idle poll after setting idle
|
||||||
dump = pool.dump();
|
dump = pool.dump();
|
||||||
assertThat(count(dump," - STARTED"),is(2));
|
assertThat(count(dump," - STARTED"),is(2));
|
||||||
assertThat(dump,containsString(",3<=3<=4,s=0,i=2,r=2,q=0"));
|
assertThat(dump,containsString(",3<=3<=4,i=2,r=2,q=0"));
|
||||||
assertThat(dump,containsString("[ReservedThreadExecutor@"));
|
assertThat(dump,containsString("[ReservedThreadExecutor@"));
|
||||||
assertThat(count(dump," IDLE "),is(2));
|
assertThat(count(dump," IDLE "),is(2));
|
||||||
assertThat(count(dump," WAITING "),is(1));
|
assertThat(count(dump," WAITING "),is(1));
|
||||||
|
@ -598,7 +632,7 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
||||||
pool.setDetailedDump(true);
|
pool.setDetailedDump(true);
|
||||||
dump = pool.dump();
|
dump = pool.dump();
|
||||||
assertThat(count(dump," - STARTED"),is(2));
|
assertThat(count(dump," - STARTED"),is(2));
|
||||||
assertThat(dump,containsString(",3<=3<=4,s=0,i=2,r=2,q=0"));
|
assertThat(dump,containsString(",3<=3<=4,i=2,r=2,q=0"));
|
||||||
assertThat(dump,containsString("s=0/2"));
|
assertThat(dump,containsString("s=0/2"));
|
||||||
assertThat(dump,containsString("[ReservedThreadExecutor@"));
|
assertThat(dump,containsString("[ReservedThreadExecutor@"));
|
||||||
assertThat(count(dump," IDLE "),is(2));
|
assertThat(count(dump," IDLE "),is(2));
|
||||||
|
@ -607,12 +641,11 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest
|
||||||
assertThat(count(dump,"QueuedThreadPoolTest.lambda$testDump$"),is(1));
|
assertThat(count(dump,"QueuedThreadPoolTest.lambda$testDump$"),is(1));
|
||||||
|
|
||||||
assertFalse(pool.tryExecute(()->{}));
|
assertFalse(pool.tryExecute(()->{}));
|
||||||
while(pool.getIdleThreads()==2)
|
waitForReserved(pool,1);
|
||||||
Thread.sleep(10);
|
Thread.sleep(250); // TODO need to give time for threads to read idle poll after setting idle
|
||||||
|
|
||||||
dump = pool.dump();
|
dump = pool.dump();
|
||||||
assertThat(count(dump," - STARTED"),is(2));
|
assertThat(count(dump," - STARTED"),is(2));
|
||||||
assertThat(dump,containsString(",3<=3<=4,s=0,i=1,r=2,q=0"));
|
assertThat(dump,containsString(",3<=3<=4,i=1,r=2,q=0"));
|
||||||
assertThat(dump,containsString("s=1/2"));
|
assertThat(dump,containsString("s=1/2"));
|
||||||
assertThat(dump,containsString("[ReservedThreadExecutor@"));
|
assertThat(dump,containsString("[ReservedThreadExecutor@"));
|
||||||
assertThat(count(dump," IDLE "),is(1));
|
assertThat(count(dump," IDLE "),is(1));
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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.websocket.jsr356.decoders;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import javax.websocket.DecodeException;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for class {@link FloatDecoder}.
|
||||||
|
*
|
||||||
|
* @see FloatDecoder
|
||||||
|
*/
|
||||||
|
public class FloatDecoderTest
|
||||||
|
{
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWillDecodeReturningTrue()
|
||||||
|
{
|
||||||
|
assertTrue(new FloatDecoder().willDecode("21"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWillDecodeReturningFalse()
|
||||||
|
{
|
||||||
|
assertFalse(new FloatDecoder().willDecode("NaN"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWillDecodeWithNull()
|
||||||
|
{
|
||||||
|
assertFalse(FloatDecoder.INSTANCE.willDecode(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDecodeThrowsDecodeException()
|
||||||
|
{
|
||||||
|
assertThrows(DecodeException.class, () -> new FloatDecoder().decode("NaN"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDecode() throws DecodeException
|
||||||
|
{
|
||||||
|
assertEquals(4.1F, new FloatDecoder().decode("4.1"), 0.01F);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -18,13 +18,14 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.websocket.jsr356.decoders;
|
package org.eclipse.jetty.websocket.jsr356.decoders;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import org.junit.jupiter.api.Test;
|
||||||
import static org.hamcrest.Matchers.is;
|
|
||||||
|
|
||||||
import javax.websocket.DecodeException;
|
import javax.websocket.DecodeException;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import org.junit.jupiter.api.Test;
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
public class IntegerDecoderTest
|
public class IntegerDecoderTest
|
||||||
{
|
{
|
||||||
|
@ -33,6 +34,26 @@ public class IntegerDecoderTest
|
||||||
{
|
{
|
||||||
IntegerDecoder decoder = new IntegerDecoder();
|
IntegerDecoder decoder = new IntegerDecoder();
|
||||||
Integer val = decoder.decode("123");
|
Integer val = decoder.decode("123");
|
||||||
assertThat("Decoded value",val,is(123));
|
assertThat("Decoded value", val, is(123));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWillDecodeWithNull()
|
||||||
|
{
|
||||||
|
assertFalse(new IntegerDecoder().willDecode(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWillDecodeWithNonEmptyString()
|
||||||
|
{
|
||||||
|
assertFalse(new IntegerDecoder().willDecode("a"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDecodeThrowsDecodeException()
|
||||||
|
{
|
||||||
|
assertThrows(DecodeException.class, () -> IntegerDecoder.INSTANCE.decode(""));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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.websocket.jsr356.decoders;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import javax.websocket.DecodeException;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for class {@link LongDecoder}.
|
||||||
|
*
|
||||||
|
* @see LongDecoder
|
||||||
|
*/
|
||||||
|
public class LongDecoderTest
|
||||||
|
{
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreatesLongDecoder()
|
||||||
|
{
|
||||||
|
assertFalse(new LongDecoder().willDecode(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWillDecodeWithNonEmptyString()
|
||||||
|
{
|
||||||
|
assertFalse(LongDecoder.INSTANCE.willDecode("Unable to parse Long"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDecodeThrowsDecodeException()
|
||||||
|
{
|
||||||
|
assertThrows(DecodeException.class, () -> LongDecoder.INSTANCE.decode("Unable to parse Long"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 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.websocket.jsr356.decoders;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import javax.websocket.DecodeException;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for class {@link ShortDecoder}.
|
||||||
|
*
|
||||||
|
* @see ShortDecoder
|
||||||
|
*/
|
||||||
|
public class ShortDecoderTest
|
||||||
|
{
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWillDecodeWithNull()
|
||||||
|
{
|
||||||
|
assertFalse(new ShortDecoder().willDecode(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWillDecodeWithNonEmptyString()
|
||||||
|
{
|
||||||
|
assertFalse(new ShortDecoder().willDecode(".iix/PN}f[&-<n$B9q"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDecodeThrowsDecodeException() throws DecodeException
|
||||||
|
{
|
||||||
|
assertThrows(DecodeException.class, () -> ShortDecoder.INSTANCE.decode("$Yta3*m*%"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -18,11 +18,13 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.websocket.common.util;
|
package org.eclipse.jetty.websocket.common.util;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.io.AbstractConnection;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for class {@link ReflectUtils}.
|
* Unit tests for class {@link ReflectUtils}.
|
||||||
|
@ -68,6 +70,18 @@ public class ReflectUtilsTest
|
||||||
assertFalse(ReflectUtils.isDefaultConstructable(Integer.class));
|
assertFalse(ReflectUtils.isDefaultConstructable(Integer.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsDefaultConstructableWithAbstractClass()
|
||||||
|
{
|
||||||
|
assertFalse(ReflectUtils.isDefaultConstructable(AbstractConnection.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsDefaultConstructableWithObjectClass()
|
||||||
|
{
|
||||||
|
assertTrue(ReflectUtils.isDefaultConstructable(Object.class));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindGenericClassForStringClassTwice()
|
public void testFindGenericClassForStringClassTwice()
|
||||||
{
|
{
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
2
pom.xml
2
pom.xml
|
@ -29,7 +29,7 @@
|
||||||
<!-- default values are unsupported, but required to be defined for reactor sanity reasons -->
|
<!-- default values are unsupported, but required to be defined for reactor sanity reasons -->
|
||||||
<alpn.version>undefined</alpn.version>
|
<alpn.version>undefined</alpn.version>
|
||||||
<conscrypt.version>2.1.0</conscrypt.version>
|
<conscrypt.version>2.1.0</conscrypt.version>
|
||||||
<asm.version>7.0</asm.version>
|
<asm.version>7.1</asm.version>
|
||||||
<jmh.version>1.21</jmh.version>
|
<jmh.version>1.21</jmh.version>
|
||||||
<jmhjar.name>benchmarks</jmhjar.name>
|
<jmhjar.name>benchmarks</jmhjar.name>
|
||||||
<tycho-version>1.2.0</tycho-version>
|
<tycho-version>1.2.0</tycho-version>
|
||||||
|
|
|
@ -8,44 +8,44 @@
|
||||||
|
|
||||||
<Call name="insertHandler">
|
<Call name="insertHandler">
|
||||||
<Arg>
|
<Arg>
|
||||||
<New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
|
<New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
|
||||||
<Set name="rewriteRequestURI">true</Set>
|
<Set name="rewriteRequestURI">true</Set>
|
||||||
<Set name="rewritePathInfo">false</Set>
|
<Set name="rewritePathInfo">false</Set>
|
||||||
<Set name="originalPathAttribute">requestedPath</Set>
|
<Set name="originalPathAttribute">requestedPath</Set>
|
||||||
|
|
||||||
<Set name="rules">
|
<Set name="rules">
|
||||||
<Array type="org.eclipse.jetty.rewrite.handler.Rule">
|
<Array type="org.eclipse.jetty.rewrite.handler.Rule">
|
||||||
|
|
||||||
<!-- add a response rule -->
|
<!-- add a response rule -->
|
||||||
<!--
|
<!--
|
||||||
<Item>
|
<Item>
|
||||||
<New id="response" class="org.eclipse.jetty.rewrite.handler.ResponsePatternRule">
|
<New id="response" class="org.eclipse.jetty.rewrite.handler.ResponsePatternRule">
|
||||||
<Set name="pattern">/rewrite/session/</Set>
|
<Set name="pattern">/rewrite/session/</Set>
|
||||||
<Set name="code">401</Set>
|
<Set name="code">401</Set>
|
||||||
<Set name="reason">Setting error code 401</Set>
|
<Set name="reason">Setting error code 401</Set>
|
||||||
</New>
|
</New>
|
||||||
</Item>
|
</Item>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!-- add a simple redirect -->
|
<!-- add a simple redirect -->
|
||||||
<!--
|
<!--
|
||||||
<Item>
|
<Item>
|
||||||
<New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule">
|
<New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule">
|
||||||
<Set name="pattern">/redirect/*</Set>
|
<Set name="pattern">/redirect/*</Set>
|
||||||
<Set name="location">/tests/</Set>
|
<Set name="location">/tests/</Set>
|
||||||
</New>
|
</New>
|
||||||
</Item>
|
</Item>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!-- add a regex rewrite redirect -->
|
<!-- add a regex rewrite redirect -->
|
||||||
<Item>
|
<Item>
|
||||||
<New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectRegexRule">
|
<New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectRegexRule">
|
||||||
<Set name="regex">/redirect/(.*)</Set>
|
<Set name="regex">/redirect/(.*)</Set>
|
||||||
<Set name="replacement">/tests/$1</Set>
|
<Set name="location">/tests/$1</Set>
|
||||||
</New>
|
</New>
|
||||||
</Item>
|
</Item>
|
||||||
</Array>
|
</Array>
|
||||||
</Set>
|
</Set>
|
||||||
</New>
|
</New>
|
||||||
</Arg>
|
</Arg>
|
||||||
</Call>
|
</Call>
|
||||||
|
|
Loading…
Reference in New Issue