diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java index f1748337b72..54819e430ed 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java @@ -49,6 +49,36 @@ public class HttpTransportOverFCGI implements HttpTransport @Override public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) + { + if (info!=null) + commit(info,content,lastContent,callback); + else + { + if (head) + { + if (lastContent) + { + Generator.Result result = generateResponseContent(BufferUtil.EMPTY_BUFFER, true, callback); + flusher.flush(result); + } + else + { + // Skip content generation + callback.succeeded(); + } + } + else + { + Generator.Result result = generateResponseContent(content, lastContent, callback); + flusher.flush(result); + } + + if (lastContent && shutdown) + flusher.shutdown(); + } + } + + private void commit(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) { boolean head = this.head = info.isHead(); boolean shutdown = this.shutdown = info.getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); @@ -78,32 +108,6 @@ public class HttpTransportOverFCGI implements HttpTransport flusher.shutdown(); } - @Override - public void send(ByteBuffer content, boolean lastContent, Callback callback) - { - if (head) - { - if (lastContent) - { - Generator.Result result = generateResponseContent(BufferUtil.EMPTY_BUFFER, true, callback); - flusher.flush(result); - } - else - { - // Skip content generation - callback.succeeded(); - } - } - else - { - Generator.Result result = generateResponseContent(content, lastContent, callback); - flusher.flush(result); - } - - if (lastContent && shutdown) - flusher.shutdown(); - } - protected Generator.Result generateResponseHeaders(HttpGenerator.ResponseInfo info, Callback callback) { return generator.generateResponseHeaders(request, info.getStatus(), info.getReason(), info.getHttpFields(), callback); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java index 7db1fa64ff0..881acbd679b 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java @@ -29,10 +29,12 @@ package org.eclipse.jetty.http; * Enum * Code * Message - * + * * RFC 1945 - HTTP/1.0 + * + * RFC 7231 - HTTP/1.1 Semantics and Content * - * RFC 2616 - HTTP/1.1 + * RFC 7238 - HTTP/1.1 Permanent Redirect * * RFC 2518 - WEBDAV * @@ -48,7 +50,7 @@ package org.eclipse.jetty.http; * Continue *   * - * Sec. 10.1.1 + * Sec. 6.2.1 *   * * @@ -57,7 +59,7 @@ package org.eclipse.jetty.http; * Switching Protocols *   * - * Sec. 10.1.2 + * Sec. 6.2.2 *   * * @@ -82,7 +84,7 @@ package org.eclipse.jetty.http; * * Sec. 9.2 * - * Sec. 10.2.1 + * Sec. 6.3.1 *   * * @@ -92,7 +94,7 @@ package org.eclipse.jetty.http; * * Sec. 9.2 * - * Sec. 10.2.2 + * Sec. 6.3.2 *   * * @@ -102,7 +104,7 @@ package org.eclipse.jetty.http; * * Sec. 9.2 * - * Sec. 10.2.3 + * Sec. 6.3.3 *   * * @@ -111,7 +113,7 @@ package org.eclipse.jetty.http; * Non Authoritative Information *   * - * Sec. 10.2.4 + * Sec. 6.3.4 *   * * @@ -121,7 +123,7 @@ package org.eclipse.jetty.http; * * Sec. 9.2 * - * Sec. 10.2.5 + * Sec. 6.3.5 *   * * @@ -130,7 +132,7 @@ package org.eclipse.jetty.http; * Reset Content *   * - * Sec. 10.2.6 + * Sec. 6.3.6 *   * * @@ -139,7 +141,7 @@ package org.eclipse.jetty.http; * Partial Content *   * - * Sec. 10.2.7 + * Sec. 6.3.7 *   * * @@ -175,7 +177,7 @@ package org.eclipse.jetty.http; * * Sec. 9.3 * - * Sec. 10.3.1 + * Sec. 6.4.1 *   * * @@ -185,7 +187,7 @@ package org.eclipse.jetty.http; * * Sec. 9.3 * - * Sec. 10.3.2 + * Sec. 6.4.2 *   * * @@ -203,7 +205,7 @@ package org.eclipse.jetty.http; * Found * (was "302 Moved Temporarily") * - * Sec. 10.3.3 + * Sec. 6.4.3 *   * * @@ -212,7 +214,7 @@ package org.eclipse.jetty.http; * See Other *   * - * Sec. 10.3.4 + * Sec. 6.4.4 *   * * @@ -222,7 +224,7 @@ package org.eclipse.jetty.http; * * Sec. 9.3 * - * Sec. 10.3.5 + * Sec. 6.4.5 *   * * @@ -231,7 +233,7 @@ package org.eclipse.jetty.http; * Use Proxy *   * - * Sec. 10.3.6 + * Sec. 6.4.6 *   * * @@ -240,7 +242,7 @@ package org.eclipse.jetty.http; * (Unused) *   * - * Sec. 10.3.7 + * Sec. 6.4.7 *   * * @@ -249,7 +251,17 @@ package org.eclipse.jetty.http; * Temporary Redirect *   * - * Sec. 10.3.8 + * Sec. 6.4.8 + *   + * + * + * + * {@link #PERMANENT_REDIRECT_308} + * 307 + * Permanent Redirect + *   + * + * RFC7238 *   * * @@ -265,7 +277,7 @@ package org.eclipse.jetty.http; * * Sec. 9.4 * - * Sec. 10.4.1 + * Sec. 6.5.1 *   * * @@ -275,7 +287,7 @@ package org.eclipse.jetty.http; * * Sec. 9.4 * - * Sec. 10.4.2 + * Sec. 6.5.2 *   * * @@ -285,7 +297,7 @@ package org.eclipse.jetty.http; * * Sec. 9.4 * - * Sec. 10.4.3 + * Sec. 6.5.3 *   * * @@ -295,7 +307,7 @@ package org.eclipse.jetty.http; * * Sec. 9.4 * - * Sec. 10.4.4 + * Sec. 6.5.4 *   * * @@ -305,7 +317,7 @@ package org.eclipse.jetty.http; * * Sec. 9.4 * - * Sec. 10.4.5 + * Sec. 6.5.5 *   * * @@ -314,7 +326,7 @@ package org.eclipse.jetty.http; * Method Not Allowed *   * - * Sec. 10.4.6 + * Sec. 6.5.6 *   * * @@ -323,7 +335,7 @@ package org.eclipse.jetty.http; * Not Acceptable *   * - * Sec. 10.4.7 + * Sec. 6.5.7 *   * * @@ -332,7 +344,7 @@ package org.eclipse.jetty.http; * Proxy Authentication Required *   * - * Sec. 10.4.8 + * Sec. 6.5.8 *   * * @@ -341,7 +353,7 @@ package org.eclipse.jetty.http; * Request Timeout *   * - * Sec. 10.4.9 + * Sec. 6.5.9 *   * * @@ -350,7 +362,7 @@ package org.eclipse.jetty.http; * Conflict *   * - * Sec. 10.4.10 + * Sec. 10.4.10 * *   * @@ -360,7 +372,7 @@ package org.eclipse.jetty.http; * Gone *   * - * Sec. 10.4.11 + * Sec. 10.4.11 * *   * @@ -370,7 +382,7 @@ package org.eclipse.jetty.http; * Length Required *   * - * Sec. 10.4.12 + * Sec. 10.4.12 * *   * @@ -380,7 +392,7 @@ package org.eclipse.jetty.http; * Precondition Failed *   * - * Sec. 10.4.13 + * Sec. 10.4.13 * *   * @@ -390,7 +402,7 @@ package org.eclipse.jetty.http; * Request Entity Too Large *   * - * Sec. 10.4.14 + * Sec. 10.4.14 * *   * @@ -400,7 +412,7 @@ package org.eclipse.jetty.http; * Request-URI Too Long *   * - * Sec. 10.4.15 + * Sec. 10.4.15 * *   * @@ -410,7 +422,7 @@ package org.eclipse.jetty.http; * Unsupported Media Type *   * - * Sec. 10.4.16 + * Sec. 10.4.16 * *   * @@ -420,7 +432,7 @@ package org.eclipse.jetty.http; * Requested Range Not Satisfiable *   * - * Sec. 10.4.17 + * Sec. 10.4.17 * *   * @@ -430,7 +442,7 @@ package org.eclipse.jetty.http; * Expectation Failed *   * - * Sec. 10.4.18 + * Sec. 10.4.18 * *   * @@ -537,7 +549,7 @@ package org.eclipse.jetty.http; * * Sec. 9.5 * - * Sec. 10.5.1 + * Sec. 6.6.1 *   * * @@ -547,7 +559,7 @@ package org.eclipse.jetty.http; * * Sec. 9.5 * - * Sec. 10.5.2 + * Sec. 6.6.2 *   * * @@ -557,7 +569,7 @@ package org.eclipse.jetty.http; * * Sec. 9.5 * - * Sec. 10.5.3 + * Sec. 6.6.3 *   * * @@ -567,7 +579,7 @@ package org.eclipse.jetty.http; * * Sec. 9.5 * - * Sec. 10.5.4 + * Sec. 6.6.4 *   * * @@ -576,7 +588,7 @@ package org.eclipse.jetty.http; * Gateway Timeout *   * - * Sec. 10.5.5 + * Sec. 6.6.5 *   * * @@ -585,7 +597,7 @@ package org.eclipse.jetty.http; * HTTP Version Not Supported *   * - * Sec. 10.5.6 + * Sec. 6.6.6 *   * * @@ -633,6 +645,7 @@ public class HttpStatus public final static int NOT_MODIFIED_304 = 304; public final static int USE_PROXY_305 = 305; public final static int TEMPORARY_REDIRECT_307 = 307; + public final static int PERMANENT_REDIRECT_308 = 308; public final static int BAD_REQUEST_400 = 400; public final static int UNAUTHORIZED_401 = 401; @@ -683,7 +696,7 @@ public class HttpStatus /* * -------------------------------------------------------------------- * Informational messages in 1xx series. As defined by ... RFC 1945 - - * HTTP/1.0 RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV + * HTTP/1.0 RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV */ /** 100 Continue */ @@ -696,7 +709,7 @@ public class HttpStatus /* * -------------------------------------------------------------------- * Success messages in 2xx series. As defined by ... RFC 1945 - HTTP/1.0 - * RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV + * RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV */ /** 200 OK */ @@ -719,7 +732,7 @@ public class HttpStatus /* * -------------------------------------------------------------------- * Redirection messages in 3xx series. As defined by ... RFC 1945 - - * HTTP/1.0 RFC 2616 - HTTP/1.1 + * HTTP/1.0 RFC 7231 - HTTP/1.1 */ /** 300 Mutliple Choices */ @@ -738,11 +751,13 @@ public class HttpStatus USE_PROXY(USE_PROXY_305, "Use Proxy"), /** 307 Temporary Redirect */ TEMPORARY_REDIRECT(TEMPORARY_REDIRECT_307, "Temporary Redirect"), + /** 308 Permanent Redirect */ + PERMANET_REDIRECT(PERMANENT_REDIRECT_308, "Permanent Redirect"), /* * -------------------------------------------------------------------- * Client Error messages in 4xx series. As defined by ... RFC 1945 - - * HTTP/1.0 RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV + * HTTP/1.0 RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV */ /** 400 Bad Request */ @@ -791,7 +806,7 @@ public class HttpStatus /* * -------------------------------------------------------------------- * Server Error messages in 5xx series. As defined by ... RFC 1945 - - * HTTP/1.0 RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV + * HTTP/1.0 RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV */ /** 500 Server Error */ @@ -844,7 +859,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * Informational message category as defined in the RFC 1945 - HTTP/1.0, - * and RFC 2616 - + * and RFC 7231 - * HTTP/1.1. * * @return true if within range of codes that belongs to @@ -859,7 +874,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * Success message category as defined in the RFC 1945 - HTTP/1.0, - * and RFC 2616 - + * and RFC 7231 - * HTTP/1.1. * * @return true if within range of codes that belongs to @@ -874,7 +889,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * Redirection message category as defined in the RFC 1945 - HTTP/1.0, - * and RFC 2616 - + * and RFC 7231 - * HTTP/1.1. * * @return true if within range of codes that belongs to @@ -889,7 +904,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * Client Error message category as defined in the RFC 1945 - HTTP/1.0, - * and RFC 2616 - + * and RFC 7231 - * HTTP/1.1. * * @return true if within range of codes that belongs to @@ -904,7 +919,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * Server Error message category as defined in the RFC 1945 - HTTP/1.0, - * and RFC 2616 - + * and RFC 7231 - * HTTP/1.1. * * @return true if within range of codes that belongs to @@ -958,7 +973,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * Informational message category as defined in the RFC 1945 - HTTP/1.0, and RFC 2616 - HTTP/1.1. + * href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1. * * @param code * the code to test. @@ -974,7 +989,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * Success message category as defined in the RFC 1945 - HTTP/1.0, and RFC 2616 - HTTP/1.1. + * href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1. * * @param code * the code to test. @@ -990,7 +1005,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * Redirection message category as defined in the RFC 1945 - HTTP/1.0, and RFC 2616 - HTTP/1.1. + * href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1. * * @param code * the code to test. @@ -1006,7 +1021,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * Client Error message category as defined in the RFC 1945 - HTTP/1.0, and RFC 2616 - HTTP/1.1. + * href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1. * * @param code * the code to test. @@ -1022,7 +1037,7 @@ public class HttpStatus * Simple test against an code to determine if it falls into the * Server Error message category as defined in the RFC 1945 - HTTP/1.0, and RFC 2616 - HTTP/1.1. + * href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1. * * @param code * the code to test. diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index 29abe5fe40a..22a44885926 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -95,6 +95,8 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF HttpTransportOverHTTP2 transport = new HttpTransportOverHTTP2((IStream)stream, frame); HttpInputOverHTTP2 input = new HttpInputOverHTTP2(); + + // TODO pool HttpChannels per connection - maybe associate with thread? HttpChannelOverHTTP2 channel = new HttpChannelOverHTTP2(connector, httpConfiguration, endPoint, transport, input, stream); stream.setAttribute(CHANNEL_ATTRIBUTE, channel); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 900736f7f38..2e0f6122c01 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -45,7 +45,7 @@ public class HttpChannelOverHTTP2 extends HttpChannel private static final HttpField ACCEPT_ENCODING_GZIP = new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip"); private static final HttpField SERVER_VERSION=new HttpField(HttpHeader.SERVER,HttpConfiguration.SERVER_VERSION); private static final HttpField POWERED_BY=new HttpField(HttpHeader.X_POWERED_BY,HttpConfiguration.SERVER_VERSION); - private final Stream stream; + private final Stream stream; // TODO recycle channel for new Stream? public HttpChannelOverHTTP2(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input, Stream stream) { diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index e9e8ad69b1e..55b9daa67e8 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -85,9 +85,8 @@ public class HttpTransportOverHTTP2 implements HttpTransport HeadersFrame frame = new HeadersFrame(stream.getId(), metaData, null, endStream); stream.headers(frame, callback); } - - @Override - public void send(ByteBuffer content, boolean lastContent, Callback callback) + + private void send(ByteBuffer content, boolean lastContent, Callback callback) { if (LOG.isDebugEnabled()) { @@ -98,6 +97,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport stream.data(frame, callback); } + @Override public void completed() { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index a07d1032f3f..94e89d42c7c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -534,7 +534,7 @@ public class HttpChannel implements Runnable else if (info==null) { // This is a normal write - _transport.send(content, complete, callback); + _transport.send(null,content, complete, callback); } else { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index d020d582484..535ce6324a0 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -443,13 +443,6 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http _sendCallback.iterate(); } - @Override - public void send(ByteBuffer content, boolean lastContent, Callback callback) - { - _sendCallback.reset(null,content,lastContent,callback); - _sendCallback.iterate(); - } - private class SendCallback extends IteratingCallback { private ResponseInfo _info; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java index 7058425f659..d04a43e9bc3 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java @@ -26,8 +26,6 @@ import org.eclipse.jetty.util.Callback; public interface HttpTransport { void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback); - - void send(ByteBuffer content, boolean lastContent, Callback callback); void completed(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 43bc0f2dc1e..4b1c23d4929 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -149,7 +149,7 @@ public class Request implements HttpServletRequest private boolean _handled = false; private boolean _paramsExtracted; private boolean _requestedSessionIdFromCookie = false; - private volatile Attributes _attributes; + private Attributes _attributes; private Authentication _authentication; private String _characterEncoding; private ContextHandler.Context _context; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index 15164a50c25..e68b6a0a4cc 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -90,12 +90,6 @@ public class ResponseTest { callback.succeeded(); } - - @Override - public void send(ByteBuffer responseBodyContent, boolean lastContent, Callback callback) - { - send(null,responseBodyContent, lastContent, callback); - } @Override public void completed() diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java index 520ad181cdd..88b690c0484 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java @@ -89,14 +89,6 @@ public class HttpTransportOverSPDY implements HttpTransport return requestHeaders; } - - @Override - public void send(ByteBuffer responseBodyContent, boolean lastContent, Callback callback) - { - // TODO can this be more efficient? - send(null, responseBodyContent, lastContent, callback); - } - @Override public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, final Callback callback) { @@ -165,7 +157,6 @@ public class HttpTransportOverSPDY implements HttpTransport } else if (!lastContent && !hasContent && info == null) throw new IllegalStateException("not lastContent, no content and no responseInfo!"); - } private void sendReply(HttpGenerator.ResponseInfo info, Callback callback, boolean close) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java new file mode 100644 index 00000000000..1159b93237b --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java @@ -0,0 +1,173 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.util.thread; + +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + + +/* ------------------------------------------------------------ */ +/** Strategies to execute Producers + */ +public abstract class ExecutionStrategy implements Runnable +{ + public interface Producer + { + /** + * Produce a task to run + * @return A task to run or null if we are complete. + */ + Runnable produce(); + + /** + * Check if there is more to produce. This method may not return valid + * results until {@link #produce()} has been called. + * @return true if this Producer may produce more tasks from {@link #produce()} + */ + boolean isMoreToProduce(); + + /** + * Called to signal production is completed + */ + void onCompleted(); + } + + protected final Producer _producer; + protected final Executor _executor; + + protected ExecutionStrategy(Producer producer, Executor executor) + { + _producer=producer; + _executor=executor; + } + + /* ------------------------------------------------------------ */ + /** Simple iterative strategy. + * Iterate over production until complete and execute each task. + */ + public static class Iterative extends ExecutionStrategy + { + public Iterative(Producer producer, Executor executor) + { + super(producer,executor); + } + + public void run() + { + try + { + // Iterate until we are complete + loop: while (true) + { + // produce a task + Runnable task=_producer.produce(); + + // if there is no task, break the loop + if (task==null) + break loop; + + // If we are still producing, + if (_producer.isMoreToProduce()) + // execute the task + _executor.execute(task); + else + { + // last task so we can run ourselves + task.run(); + break loop; + } + } + } + finally + { + _producer.onCompleted(); + } + } + } + + /* ------------------------------------------------------------ */ + /** + * A Strategy that allows threads to run the tasks that they have produced, + * so execution is done with a hot cache (ie threads eat what they kill). + */ + public static class EatWhatYouKill extends ExecutionStrategy + { + private final AtomicInteger _threads = new AtomicInteger(0); + private final AtomicReference _producing = new AtomicReference(Boolean.FALSE); + private volatile boolean _dispatched; + + public EatWhatYouKill(Producer producer, Executor executor) + { + super(producer,executor); + } + + public void run() + { + _dispatched=false; + // count the dispatched threads + _threads.incrementAndGet(); + try + { + boolean complete=false; + loop: while (!complete) + { + // If another thread is already producing, + if (!_producing.compareAndSet(false,true)) + // break the loop even if not complete + break loop; + + // If we got here, then we are the thread that is producing + Runnable task=null; + try + { + task=_producer.produce(); + complete=task==null || _producer.isMoreToProduce(); + } + finally + { + _producing.set(false); + } + + // then we may need another thread to keep producing + if (!complete && !_dispatched) + { + // Dispatch a thread to continue producing + _dispatched=true; + _executor.execute(this); + } + + // If there is a task, + if (task!=null) + // run the task + task.run(); + } + + } + finally + { + // If we were the last thread, signal completion + if (_threads.decrementAndGet()==0) + _producer.onCompleted(); + } + } + } + +}