>();
-+ this.service = service;
-+ this.task = task;
-+ }
-+
-+ public void reschedule(long timeOut, TimeUnit timeUnit) {
-+ ScheduledFuture> future = reference.getAndSet(null);
-+
-+ if(future != null) {
-+ if(future.cancel(false)) {
-+ future = service.schedule(task, timeOut == 0 ? Integer.MAX_VALUE : timeOut, timeOut == 0 ? TimeUnit.SECONDS : timeUnit);
-+ reference.set(future);
-+ }
-+ } else {
-+ future = service.schedule(task, timeOut == 0 ? Integer.MAX_VALUE : timeOut, timeOut == 0 ? TimeUnit.SECONDS : timeUnit);
-+ reference.set(future);
-+ }
-+ }
-+ }
-+
-+ private static final class TimeoutDispatcher implements Runnable {
-+
-+ private final ResponseWriter writer;
-+ private final TimeoutHandler handler;
-+
-+ public TimeoutDispatcher(ResponseWriter writer, TimeoutHandler handler) {
-+ this.writer = writer;
-+ this.handler = handler;
-+ }
-+
-+ public void run() {
-+ try {
-+ handler.onTimeout(writer);
-+ } catch(Exception e) {
-+ logger.log(Level.INFO, "Failed to call timeout handler", e);
-+ }
-+ }
-+ }
-+
- @Override
- public void handle(final Request request, final Response response) {
-- final Writer responseWriter = new Writer(response);
-+ final ResponseWriter responseWriter = new ResponseWriter(response, scheduler);
- final URI baseUri = getBaseUri(request);
- final URI requestUri = getRequestUri(request, baseUri);
-
-@@ -261,7 +348,9 @@
- } catch (final Exception ex) {
- throw new RuntimeException(ex);
- } finally {
-- close(response);
-+ if(!responseWriter.isSuspended()) {
-+ close(response);
-+ }
- }
- }
-
-@@ -316,7 +405,7 @@
-
- @Override
- public Principal getUserPrincipal() {
-- return request.getSecuritySession().getLocalPrincipal();
-+ return null;
- }
-
- @Override
-@@ -348,7 +437,8 @@
- public void reload(final ResourceConfig configuration) {
- appHandler.onShutdown(this);
-
-- appHandler = new ApplicationHandler(configuration.register(new SimpleBinder()));
-+ appHandler = new ApplicationHandler(configuration.register(new SimpleBinder()));
-+ scheduler = new ScheduledThreadPoolExecutor(2, new DaemonFactory(TimeoutDispatcher.class));
- appHandler.onReload(this);
- appHandler.onStartup(this);
- }
-@@ -374,6 +464,7 @@
- */
- void onServerStop() {
- appHandler.onShutdown(this);
-+ scheduler.shutdown();
- }
-
- /**
-@@ -384,6 +475,7 @@
- */
- SimpleContainer(final Application application, final ServiceLocator parentLocator) {
- this.appHandler = new ApplicationHandler(application, new SimpleBinder(), parentLocator);
-+ this.scheduler = new ScheduledThreadPoolExecutor(2, new DaemonFactory(TimeoutDispatcher.class));
- }
-
- /**
-@@ -393,5 +485,6 @@
- */
- SimpleContainer(final Application application) {
- this.appHandler = new ApplicationHandler(application, new SimpleBinder());
-+ this.scheduler = new ScheduledThreadPoolExecutor(2, new DaemonFactory(TimeoutDispatcher.class));
- }
- }
-diff -Nru jersey-2.23.1/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java jersey-2.23.1.simple/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java
---- jersey-2.23.1/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java 2016-06-09 20:03:52.000000000 +0200
-+++ jersey-2.23.1.simple/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java 2016-07-27 11:20:16.619503481 +0200
-@@ -50,5 +50,34 @@
- */
- public interface SimpleServer extends Closeable {
-
-+ /**
-+ * The port the server is listening to for incomming HTTP connections. If the
-+ * port is not specified the {@linke org.glassfish.jersey.server.spi.Container.DEFAULT_PORT}
-+ * is used.
-+ *
-+ * @return the port the server is listening on
-+ */
- public int getPort();
-+
-+ /**
-+ * If this is true then very low level I/O operations are logged. Typically this is used
-+ * to debug I/O issues such as HTTPS handshakes or performance issues by analysing the
-+ * various latencies involved in the HTTP conversation.
-+ *
-+ * There is a minimal performance penalty if this is enabled and it is perfectly suited
-+ * to being enabled in a production environment, at the cost of logging overhead.
-+ *
-+ * @return true if debug is enabled, false otherwise
-+ */
-+ public boolean isDebug();
-+
-+ /**
-+ * To enable very low level logging this can be enabled. This goes far beyond logging
-+ * issues such as connection establishment of request dispatch, it can trace the TCP
-+ * operations latencies involved.
-+ *
-+ * @param enable if true debug tracing will be enabled
-+ */
-+ public void setDebug(boolean enable);
-+
- }
-diff -Nru jersey-2.23.1/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleTraceAnalyzer.java jersey-2.23.1.simple/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleTraceAnalyzer.java
---- jersey-2.23.1/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleTraceAnalyzer.java 1970-01-01 01:00:00.000000000 +0100
-+++ jersey-2.23.1.simple/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleTraceAnalyzer.java 2016-07-27 09:54:22.000000000 +0200
-@@ -0,0 +1,177 @@
-+package org.glassfish.jersey.simple;
-+
-+import java.io.PrintWriter;
-+import java.io.StringWriter;
-+import java.nio.channels.SelectableChannel;
-+import java.util.Queue;
-+import java.util.concurrent.ConcurrentLinkedQueue;
-+import java.util.concurrent.ThreadFactory;
-+import java.util.concurrent.atomic.AtomicBoolean;
-+import java.util.concurrent.atomic.AtomicLong;
-+import java.util.logging.Level;
-+import java.util.logging.Logger;
-+
-+import org.glassfish.jersey.internal.util.ExtendedLogger;
-+import org.simpleframework.common.thread.DaemonFactory;
-+import org.simpleframework.transport.trace.Trace;
-+import org.simpleframework.transport.trace.TraceAnalyzer;
-+
-+/**
-+ * Tracing at a very low level can be performed with a {@link TraceAnalyzer}. This provides much
-+ * more useful information than the conventional {@link LoggingFilter} in that it provides
-+ * details at a very low level. This is very useful when monitoring performance interactions
-+ * at the TCP level between clients and servers.
-+ *
-+ * Performance overhead for the server is minimal as events are pumped out in batches. The
-+ * amount of logging information will increase quite significantly though.
-+ *
-+ * @author Niall Gallagher
-+ */
-+public class SimpleTraceAnalyzer implements TraceAnalyzer {
-+
-+ private static final ExtendedLogger logger = new ExtendedLogger(Logger.getLogger(SimpleTraceAnalyzer.class.getName()), Level.FINEST);
-+
-+ private final TraceConsumer consumer;
-+ private final ThreadFactory factory;
-+ private final AtomicBoolean active;
-+ private final AtomicLong count;
-+
-+ public SimpleTraceAnalyzer() {
-+ this.factory = new DaemonFactory(TraceConsumer.class);
-+ this.consumer = new TraceConsumer();
-+ this.active = new AtomicBoolean();
-+ this.count = new AtomicLong();
-+ }
-+
-+ public boolean isActive() {
-+ return active.get();
-+ }
-+
-+ @Override
-+ public Trace attach(SelectableChannel channel) {
-+ long sequence = count.getAndIncrement();
-+ return new TraceFeeder(channel, sequence);
-+ }
-+
-+ public void start() {
-+ if(active.compareAndSet(false, true)) {
-+ Thread thread = factory.newThread(consumer);
-+ thread.start();
-+ }
-+ }
-+
-+ @Override
-+ public void stop() {
-+ active.set(false);
-+ }
-+
-+ private class TraceConsumer implements Runnable {
-+
-+ private final Queue queue;
-+
-+ public TraceConsumer() {
-+ this.queue = new ConcurrentLinkedQueue();
-+ }
-+
-+ public void consume(TraceRecord record) {
-+ queue.offer(record);
-+ }
-+
-+ public void run() {
-+ try {
-+ while(active.get()) {
-+ Thread.sleep(1000);
-+ drain();
-+ }
-+ } catch(Exception e) {
-+ logger.info("Trace analyzer error");
-+ } finally {
-+ try {
-+ drain();
-+ } catch(Exception e) {
-+ logger.info("Trace analyzer could not drain queue");
-+ }
-+ active.set(false);
-+ }
-+
-+ }
-+
-+ private void drain() {
-+ while(!queue.isEmpty()) {
-+ TraceRecord record = queue.poll();
-+
-+ if(record != null) {
-+ String message = record.toString();
-+ logger.info(message);
-+ }
-+ }
-+ }
-+ }
-+
-+ private class TraceFeeder implements Trace {
-+
-+ private final SelectableChannel channel;
-+ private final long sequence;
-+
-+ public TraceFeeder(SelectableChannel channel, long sequence) {
-+ this.sequence = sequence;
-+ this.channel = channel;
-+ }
-+
-+ @Override
-+ public void trace(Object event) {
-+ trace(event, null);
-+ }
-+
-+ @Override
-+ public void trace(Object event, Object value) {
-+ if(active.get()) {
-+ TraceRecord record = new TraceRecord(channel, event, value, sequence);
-+ consumer.consume(record);
-+ }
-+ }
-+
-+ }
-+
-+ private class TraceRecord {
-+
-+ private final SelectableChannel channel;
-+ private final String thread;
-+ private final Object event;
-+ private final Object value;
-+ private final long sequence;
-+
-+ public TraceRecord(SelectableChannel channel, Object event, Object value, long sequence) {
-+ this.thread = Thread.currentThread().getName();
-+ this.sequence = sequence;
-+ this.channel = channel;
-+ this.event = event;
-+ this.value = value;
-+ }
-+
-+ public String toString() {
-+ StringWriter builder = new StringWriter();
-+ PrintWriter writer = new PrintWriter(builder);
-+
-+ writer.print(sequence);
-+ writer.print(" ");
-+ writer.print(channel);
-+ writer.print(" (");
-+ writer.print(thread);
-+ writer.print("): ");
-+ writer.print(event);
-+
-+ if(value != null) {
-+ if(value instanceof Throwable) {
-+ writer.print(" -> ");
-+ ((Throwable)value).printStackTrace(writer);
-+ } else {
-+ writer.print(" -> ");
-+ writer.print(value);
-+ }
-+ }
-+ writer.close();
-+ return builder.toString();
-+ }
-+ }
-+}
-diff -Nru jersey-2.23.1/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java jersey-2.23.1.simple/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java
---- jersey-2.23.1/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java 2016-06-09 20:03:52.000000000 +0200
-+++ jersey-2.23.1.simple/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java 2016-07-27 11:28:02.254502511 +0200
-@@ -94,7 +94,7 @@
- return DEFAULT_PORT;
- }
-
-- private volatile Closeable server;
-+ private volatile SimpleServer server;
-
- public UriBuilder getUri() {
- return UriBuilder.fromUri("http://localhost").port(getPort()).path(CONTEXT);
-@@ -108,6 +108,13 @@
- LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri);
- }
-
-+ public void startServerNoLoggingFilter(Class... resources) {
-+ ResourceConfig config = new ResourceConfig(resources);
-+ final URI baseUri = getBaseUri();
-+ server = SimpleContainerFactory.create(baseUri, config);
-+ LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri);
-+ }
-+
- public void startServer(ResourceConfig config) {
- final URI baseUri = getBaseUri();
- config.register(LoggingFeature.class);
-@@ -126,6 +133,12 @@
- return UriBuilder.fromUri("http://localhost/").port(getPort()).build();
- }
-
-+ public void setDebug(boolean enable) {
-+ if(server != null) {
-+ server.setDebug(enable);
-+ }
-+ }
-+
- public void stopServer() {
- try {
- server.close();
-diff -Nru jersey-2.23.1/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AsyncTest.java jersey-2.23.1.simple/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AsyncTest.java
---- jersey-2.23.1/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AsyncTest.java 1970-01-01 01:00:00.000000000 +0100
-+++ jersey-2.23.1.simple/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AsyncTest.java 2016-07-27 09:54:22.000000000 +0200
-@@ -0,0 +1,193 @@
-+/*
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
-+ *
-+ * Copyright (c) 2013-2015 Oracle and/or its affiliates. All rights reserved.
-+ *
-+ * The contents of this file are subject to the terms of either the GNU
-+ * General Public License Version 2 only ("GPL") or the Common Development
-+ * and Distribution License("CDDL") (collectively, the "License"). You
-+ * may not use this file except in compliance with the License. You can
-+ * obtain a copy of the License at
-+ * http://glassfish.java.net/public/CDDL+GPL_1_1.html
-+ * or packager/legal/LICENSE.txt. See the License for the specific
-+ * language governing permissions and limitations under the License.
-+ *
-+ * When distributing the software, include this License Header Notice in each
-+ * file and include the License file at packager/legal/LICENSE.txt.
-+ *
-+ * GPL Classpath Exception:
-+ * Oracle designates this particular file as subject to the "Classpath"
-+ * exception as provided by Oracle in the GPL Version 2 section of the License
-+ * file that accompanied this code.
-+ *
-+ * Modifications:
-+ * If applicable, add the following below the License Header, with the fields
-+ * enclosed by brackets [] replaced by your own identifying information:
-+ * "Portions Copyright [year] [name of copyright owner]"
-+ *
-+ * Contributor(s):
-+ * If you wish your version of this file to be governed by only the CDDL or
-+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
-+ * elects to include this software in this distribution under the [CDDL or GPL
-+ * Version 2] license." If you don't indicate a single choice of license, a
-+ * recipient has the option to distribute your version of this file under
-+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
-+ * its licensees as provided above. However, if you add GPL Version 2 code
-+ * and therefore, elected the GPL Version 2 license, then the option applies
-+ * only if the new code is made subject to such option by the copyright
-+ * holder.
-+ */
-+package org.glassfish.jersey.simple;
-+
-+import static org.hamcrest.CoreMatchers.is;
-+import static org.junit.Assert.assertEquals;
-+import static org.junit.Assert.assertThat;
-+
-+import java.util.concurrent.ExecutionException;
-+import java.util.concurrent.Future;
-+import java.util.concurrent.TimeUnit;
-+import java.util.concurrent.TimeoutException;
-+import java.util.concurrent.atomic.AtomicInteger;
-+
-+import javax.ws.rs.GET;
-+import javax.ws.rs.Path;
-+import javax.ws.rs.client.Client;
-+import javax.ws.rs.client.ClientBuilder;
-+import javax.ws.rs.container.AsyncResponse;
-+import javax.ws.rs.container.Suspended;
-+import javax.ws.rs.container.TimeoutHandler;
-+import javax.ws.rs.core.Response;
-+
-+import org.junit.After;
-+import org.junit.Before;
-+import org.junit.Test;
-+
-+/**
-+ * @author Arul Dhesiaseelan (aruld at acm.org)
-+ * @author Michal Gajdos
-+ */
-+public class AsyncTest extends AbstractSimpleServerTester {
-+
-+ @Path("/async")
-+ @SuppressWarnings("VoidMethodAnnotatedWithGET")
-+ public static class AsyncResource {
-+
-+ public static AtomicInteger INVOCATION_COUNT = new AtomicInteger(0);
-+
-+ @GET
-+ public void asyncGet(@Suspended final AsyncResponse asyncResponse) {
-+ new Thread(new Runnable() {
-+
-+ @Override
-+ public void run() {
-+ final String result = veryExpensiveOperation();
-+ asyncResponse.resume(result);
-+ }
-+
-+ private String veryExpensiveOperation() {
-+ // ... very expensive operation that typically finishes within 5 seconds, simulated using sleep()
-+ try {
-+ Thread.sleep(5000);
-+ } catch (final InterruptedException e) {
-+ // ignore
-+ }
-+ return "DONE";
-+ }
-+ }).start();
-+ }
-+
-+ @GET
-+ @Path("timeout")
-+ public void asyncGetWithTimeout(@Suspended final AsyncResponse asyncResponse) {
-+ asyncResponse.setTimeoutHandler(new TimeoutHandler() {
-+
-+ @Override
-+ public void handleTimeout(final AsyncResponse asyncResponse) {
-+ asyncResponse.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("Operation time out.")
-+ .build());
-+ }
-+ });
-+ asyncResponse.setTimeout(3, TimeUnit.SECONDS);
-+
-+ new Thread(new Runnable() {
-+
-+ @Override
-+ public void run() {
-+ final String result = veryExpensiveOperation();
-+ asyncResponse.resume(result);
-+ }
-+
-+ private String veryExpensiveOperation() {
-+ // ... very expensive operation that typically finishes within 10 seconds, simulated using sleep()
-+ try {
-+ Thread.sleep(7000);
-+ } catch (final InterruptedException e) {
-+ // ignore
-+ }
-+ return "DONE";
-+ }
-+ }).start();
-+ }
-+
-+ @GET
-+ @Path("multiple-invocations")
-+ public void asyncMultipleInvocations(@Suspended final AsyncResponse asyncResponse) {
-+ INVOCATION_COUNT.incrementAndGet();
-+
-+ new Thread(new Runnable() {
-+ @Override
-+ public void run() {
-+ asyncResponse.resume("OK");
-+ }
-+ }).start();
-+ }
-+ }
-+
-+ private Client client;
-+
-+ @Before
-+ public void setUp() throws Exception {
-+ startServer(AsyncResource.class);
-+ client = ClientBuilder.newClient();
-+ }
-+
-+ @Override
-+ @After
-+ public void tearDown() {
-+ super.tearDown();
-+ client = null;
-+ }
-+
-+ @Test
-+ public void testAsyncGet() throws ExecutionException, InterruptedException {
-+ final Future responseFuture = client.target(getUri().path("/async")).request().async().get();
-+ // Request is being processed asynchronously.
-+ final Response response = responseFuture.get();
-+ // get() waits for the response
-+ assertEquals("DONE", response.readEntity(String.class));
-+ }
-+
-+ @Test
-+ public void testAsyncGetWithTimeout() throws ExecutionException, InterruptedException, TimeoutException {
-+ final Future responseFuture = client.target(getUri().path("/async/timeout")).request().async().get();
-+ // Request is being processed asynchronously.
-+ final Response response = responseFuture.get();
-+
-+ // get() waits for the response
-+ assertEquals(503, response.getStatus());
-+ assertEquals("Operation time out.", response.readEntity(String.class));
-+ }
-+
-+ /**
-+ * JERSEY-2616 reproducer. Make sure resource method is only invoked once per one request.
-+ */
-+ @Test
-+ public void testAsyncMultipleInvocations() throws Exception {
-+ final Response response = client.target(getUri().path("/async/multiple-invocations")).request().get();
-+
-+ assertThat(AsyncResource.INVOCATION_COUNT.get(), is(1));
-+
-+ assertThat(response.getStatus(), is(200));
-+ assertThat(response.readEntity(String.class), is("OK"));
-+ }
-+}
-diff -Nru jersey-2.23.1/containers/simple-http/src/test/java/org/glassfish/jersey/simple/TraceTest.java jersey-2.23.1.simple/containers/simple-http/src/test/java/org/glassfish/jersey/simple/TraceTest.java
---- jersey-2.23.1/containers/simple-http/src/test/java/org/glassfish/jersey/simple/TraceTest.java 1970-01-01 01:00:00.000000000 +0100
-+++ jersey-2.23.1.simple/containers/simple-http/src/test/java/org/glassfish/jersey/simple/TraceTest.java 2016-07-27 09:54:22.000000000 +0200
-@@ -0,0 +1,89 @@
-+package org.glassfish.jersey.simple;
-+
-+import static org.hamcrest.CoreMatchers.is;
-+import static org.hamcrest.MatcherAssert.assertThat;
-+import static org.junit.Assert.assertEquals;
-+import static org.junit.Assert.assertTrue;
-+
-+import javax.ws.rs.GET;
-+import javax.ws.rs.Path;
-+import javax.ws.rs.Produces;
-+import javax.ws.rs.client.Client;
-+import javax.ws.rs.client.ClientBuilder;
-+import javax.ws.rs.core.Response;
-+
-+import org.junit.After;
-+import org.junit.Before;
-+import org.junit.Test;
-+
-+public class TraceTest extends AbstractSimpleServerTester {
-+
-+ @Path("helloworld")
-+ public static class HelloWorldResource {
-+ public static final String CLICHED_MESSAGE = "Hello World!";
-+
-+ @GET
-+ @Produces("text/plain")
-+ public String getHello() {
-+ return CLICHED_MESSAGE;
-+ }
-+ }
-+
-+ @Path("/users")
-+ public class UserResource {
-+
-+ @Path("/current")
-+ @GET
-+ @Produces("text/plain")
-+ public String getCurrentUser() {
-+ return "current user";
-+ }
-+ }
-+
-+ private Client client;
-+
-+ @Before
-+ public void setUp() throws Exception {
-+ startServerNoLoggingFilter(HelloWorldResource.class, UserResource.class); // disable crude LoggingFilter
-+ setDebug(true);
-+ client = ClientBuilder.newClient();
-+ }
-+
-+ @Override
-+ @After
-+ public void tearDown() {
-+ super.tearDown();
-+ client = null;
-+ }
-+
-+
-+ @Test
-+ public void testFooBarOptions() {
-+ for(int i = 0; i < 100; i++) {
-+ Response response = client.target(getUri()).path("helloworld").request().header("Accept", "foo/bar").options();
-+ assertEquals(200, response.getStatus());
-+ final String allowHeader = response.getHeaderString("Allow");
-+ _checkAllowContent(allowHeader);
-+ assertEquals(0, response.getLength());
-+ assertEquals("foo/bar", response.getMediaType().toString());
-+
-+ try {
-+ Thread.sleep(50);
-+ } catch(Exception e) {
-+ e.printStackTrace();
-+ }
-+ }
-+ }
-+
-+ private void _checkAllowContent(final String content) {
-+ assertTrue(content.contains("GET"));
-+ assertTrue(content.contains("HEAD"));
-+ assertTrue(content.contains("OPTIONS"));
-+ }
-+
-+ @Test
-+ public void testNoDefaultMethod() {
-+ Response response = client.target(getUri()).path("/users").request().options();
-+ assertThat(response.getStatus(), is(404));
-+ }
-+}
-diff -Nru jersey-2.23.1/pom.xml jersey-2.23.1.simple/pom.xml
---- jersey-2.23.1/pom.xml 2016-06-09 20:03:52.000000000 +0200
-+++ jersey-2.23.1.simple/pom.xml 2016-07-27 11:29:36.308056659 +0200
-@@ -1483,7 +1483,17 @@
-
-
- org.simpleframework
-- simple
-+ simple-common
-+ ${simple.version}
-+
-+
-+ org.simpleframework
-+ simple-http
-+ ${simple.version}
-+
-+
-+ org.simpleframework
-+ simple-transport
- ${simple.version}
-
-
-@@ -1927,7 +1937,7 @@
- 1.0.12
- 2.4
- 3.0.1
-- 5.1.4
-+ 6.0.1
- 1.7.12
- 3.2.3.RELEASE
- 1.1.0.Final
diff --git a/jersey-2.23.2-port-to-simple6.patch b/jersey-2.23.2-port-to-simple6.patch
new file mode 100644
index 0000000..16579f6
--- /dev/null
+++ b/jersey-2.23.2-port-to-simple6.patch
@@ -0,0 +1,910 @@
+diff -Nru jersey-2.23.2/containers/simple-http/pom.xml jersey-2.23.2.simple/containers/simple-http/pom.xml
+--- jersey-2.23.2/containers/simple-http/pom.xml 2016-08-08 19:11:27.000000000 +0200
++++ jersey-2.23.2.simple/containers/simple-http/pom.xml 2016-09-28 13:59:48.888238051 +0200
+@@ -61,7 +61,15 @@
+
+
+ org.simpleframework
+- simple
++ simple-common
++
++
++ org.simpleframework
++ simple-http
++
++
++ org.simpleframework
++ simple-transport
+
+
+
+diff -Nru jersey-2.23.2/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainerFactory.java jersey-2.23.2.simple/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainerFactory.java
+--- jersey-2.23.2/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainerFactory.java 2016-08-08 19:11:27.000000000 +0200
++++ jersey-2.23.2.simple/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainerFactory.java 2016-09-28 13:59:48.889237999 +0200
+@@ -57,8 +57,8 @@
+ import org.glassfish.hk2.api.ServiceLocator;
+
+ import org.simpleframework.http.core.Container;
+-import org.simpleframework.http.core.ContainerServer;
+-import org.simpleframework.transport.Server;
++import org.simpleframework.http.core.ContainerSocketProcessor;
++import org.simpleframework.transport.SocketProcessor;
+ import org.simpleframework.transport.connect.Connection;
+ import org.simpleframework.transport.connect.SocketConnection;
+
+@@ -180,10 +180,10 @@
+ public static SimpleServer create(final URI address,
+ final SSLContext context,
+ final SimpleContainer container) {
+- return _create(address, context, container, new UnsafeValue() {
++ return _create(address, context, container, new UnsafeValue() {
+ @Override
+- public Server get() throws IOException {
+- return new ContainerServer(container);
++ public SocketProcessor get() throws IOException {
++ return new ContainerSocketProcessor(container);
+ }
+ });
+ }
+@@ -241,10 +241,10 @@
+ final int count,
+ final int select) throws ProcessingException {
+
+- return _create(address, context, container, new UnsafeValue() {
++ return _create(address, context, container, new UnsafeValue() {
+ @Override
+- public Server get() throws IOException {
+- return new ContainerServer(container, count, select);
++ public SocketProcessor get() throws IOException {
++ return new ContainerSocketProcessor(container, count, select);
+ }
+ });
+ }
+@@ -252,7 +252,7 @@
+ private static SimpleServer _create(final URI address,
+ final SSLContext context,
+ final SimpleContainer container,
+- final UnsafeValue serverProvider) throws ProcessingException {
++ final UnsafeValue serverProvider) throws ProcessingException {
+ if (address == null) {
+ throw new IllegalArgumentException(LocalizationMessages.URI_CANNOT_BE_NULL());
+ }
+@@ -277,8 +277,9 @@
+ final InetSocketAddress listen = new InetSocketAddress(port);
+ final Connection connection;
+ try {
+- final Server server = serverProvider.get();
+- connection = new SocketConnection(server);
++ final SimpleTraceAnalyzer analyzer = new SimpleTraceAnalyzer();
++ final SocketProcessor server = serverProvider.get();
++ connection = new SocketConnection(server, analyzer);
+
+ final SocketAddress socketAddr = connection.connect(listen, context);
+ container.onServerStart();
+@@ -288,6 +289,7 @@
+ @Override
+ public void close() throws IOException {
+ container.onServerStop();
++ analyzer.stop();
+ connection.close();
+ }
+
+@@ -295,6 +297,21 @@
+ public int getPort() {
+ return ((InetSocketAddress) socketAddr).getPort();
+ }
++
++ @Override
++ public boolean isDebug() {
++ return analyzer.isActive();
++ }
++
++ @Override
++ public void setDebug(boolean enable) {
++ if(enable) {
++ analyzer.start();
++ } else {
++ analyzer.stop();
++ }
++ }
++
+ };
+ } catch (final IOException ex) {
+ throw new ProcessingException(LocalizationMessages.ERROR_WHEN_CREATING_SERVER(), ex);
+diff -Nru jersey-2.23.2/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java jersey-2.23.2.simple/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java
+--- jersey-2.23.2/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java 2016-08-08 19:11:27.000000000 +0200
++++ jersey-2.23.2.simple/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java 2016-09-28 13:59:48.889237999 +0200
+@@ -47,7 +47,11 @@
+ import java.security.Principal;
+ import java.util.List;
+ import java.util.Map;
++import java.util.concurrent.ScheduledExecutorService;
++import java.util.concurrent.ScheduledFuture;
++import java.util.concurrent.ScheduledThreadPoolExecutor;
+ import java.util.concurrent.TimeUnit;
++import java.util.concurrent.atomic.AtomicReference;
+ import java.util.logging.Level;
+ import java.util.logging.Logger;
+
+@@ -70,16 +74,20 @@
+ import org.glassfish.jersey.server.internal.ContainerUtils;
+ import org.glassfish.jersey.server.spi.Container;
+ import org.glassfish.jersey.server.spi.ContainerResponseWriter;
++import org.glassfish.jersey.server.spi.ContainerResponseWriter.TimeoutHandler;
+ import org.glassfish.jersey.server.spi.RequestScopedInitializer;
+
+ import org.glassfish.hk2.api.ServiceLocator;
+ import org.glassfish.hk2.api.TypeLiteral;
+ import org.glassfish.hk2.utilities.binding.AbstractBinder;
+
++import org.simpleframework.common.thread.DaemonFactory;
+ import org.simpleframework.http.Address;
++import org.simpleframework.http.Protocol;
+ import org.simpleframework.http.Request;
+ import org.simpleframework.http.Response;
+ import org.simpleframework.http.Status;
++import org.simpleframework.http.parse.PrincipalParser;
+
+ /**
+ * Jersey {@code Container} implementation based on Simple framework {@link org.simpleframework.http.core.Container}.
+@@ -141,14 +149,19 @@
+ }
+ }
+
++ private volatile ScheduledExecutorService scheduler;
+ private volatile ApplicationHandler appHandler;
+
+- private static final class Writer implements ContainerResponseWriter {
++ private static final class ResponseWriter implements ContainerResponseWriter {
+
++ private final AtomicReference reference;
++ private final ScheduledExecutorService scheduler;
+ private final Response response;
+
+- Writer(final Response response) {
++ ResponseWriter(final Response response, final ScheduledExecutorService scheduler) {
++ this.reference = new AtomicReference();
+ this.response = response;
++ this.scheduler = scheduler;
+ }
+
+ @Override
+@@ -177,12 +190,36 @@
+
+ @Override
+ public boolean suspend(final long timeOut, final TimeUnit timeUnit, final TimeoutHandler timeoutHandler) {
+- throw new UnsupportedOperationException("Method suspend is not supported by the container.");
++ try {
++ TimeoutTimer timer = reference.get();
++
++ if(timer == null) {
++ TimeoutDispatcher task = new TimeoutDispatcher(this, timeoutHandler);
++ ScheduledFuture> future = scheduler.schedule(task, timeOut == 0 ? Integer.MAX_VALUE : timeOut, timeOut == 0 ? TimeUnit.SECONDS : timeUnit);
++ timer = new TimeoutTimer(scheduler, future, task);
++ reference.set(timer);
++ return true;
++ }
++ return false;
++ } catch (final IllegalStateException ex) {
++ return false;
++ } finally {
++ logger.debugLog("suspend(...) called");
++ }
+ }
+
+ @Override
+ public void setSuspendTimeout(final long timeOut, final TimeUnit timeUnit) throws IllegalStateException {
+- throw new UnsupportedOperationException("Method suspend is not supported by the container.");
++ try {
++ TimeoutTimer timer = reference.get();
++
++ if(timer == null) {
++ throw new IllegalStateException("Response has not been suspended");
++ }
++ timer.reschedule(timeOut, timeUnit);
++ } finally {
++ logger.debugLog("setTimeout(...) called");
++ }
+ }
+
+ @Override
+@@ -196,6 +233,10 @@
+ }
+ }
+
++ public boolean isSuspended() {
++ return reference.get() != null;
++ }
++
+ @Override
+ public void failure(final Throwable error) {
+ try {
+@@ -231,9 +272,55 @@
+
+ }
+
++ private static final class TimeoutTimer {
++
++ private final AtomicReference> reference;
++ private final ScheduledExecutorService service;
++ private final TimeoutDispatcher task;
++
++ public TimeoutTimer(ScheduledExecutorService service, ScheduledFuture> future, TimeoutDispatcher task) {
++ this.reference = new AtomicReference>();
++ this.service = service;
++ this.task = task;
++ }
++
++ public void reschedule(long timeOut, TimeUnit timeUnit) {
++ ScheduledFuture> future = reference.getAndSet(null);
++
++ if(future != null) {
++ if(future.cancel(false)) {
++ future = service.schedule(task, timeOut == 0 ? Integer.MAX_VALUE : timeOut, timeOut == 0 ? TimeUnit.SECONDS : timeUnit);
++ reference.set(future);
++ }
++ } else {
++ future = service.schedule(task, timeOut == 0 ? Integer.MAX_VALUE : timeOut, timeOut == 0 ? TimeUnit.SECONDS : timeUnit);
++ reference.set(future);
++ }
++ }
++ }
++
++ private static final class TimeoutDispatcher implements Runnable {
++
++ private final ResponseWriter writer;
++ private final TimeoutHandler handler;
++
++ public TimeoutDispatcher(ResponseWriter writer, TimeoutHandler handler) {
++ this.writer = writer;
++ this.handler = handler;
++ }
++
++ public void run() {
++ try {
++ handler.onTimeout(writer);
++ } catch(Exception e) {
++ logger.log(Level.INFO, "Failed to call timeout handler", e);
++ }
++ }
++ }
++
+ @Override
+ public void handle(final Request request, final Response response) {
+- final Writer responseWriter = new Writer(response);
++ final ResponseWriter responseWriter = new ResponseWriter(response, scheduler);
+ final URI baseUri = getBaseUri(request);
+ final URI requestUri = getRequestUri(request, baseUri);
+
+@@ -261,7 +348,9 @@
+ } catch (final Exception ex) {
+ throw new RuntimeException(ex);
+ } finally {
+- close(response);
++ if(!responseWriter.isSuspended()) {
++ close(response);
++ }
+ }
+ }
+
+@@ -316,7 +405,7 @@
+
+ @Override
+ public Principal getUserPrincipal() {
+- return request.getSecuritySession().getLocalPrincipal();
++ return null;
+ }
+
+ @Override
+@@ -348,7 +437,8 @@
+ public void reload(final ResourceConfig configuration) {
+ appHandler.onShutdown(this);
+
+- appHandler = new ApplicationHandler(configuration.register(new SimpleBinder()));
++ appHandler = new ApplicationHandler(configuration.register(new SimpleBinder()));
++ scheduler = new ScheduledThreadPoolExecutor(2, new DaemonFactory(TimeoutDispatcher.class));
+ appHandler.onReload(this);
+ appHandler.onStartup(this);
+ }
+@@ -374,6 +464,7 @@
+ */
+ void onServerStop() {
+ appHandler.onShutdown(this);
++ scheduler.shutdown();
+ }
+
+ /**
+@@ -384,6 +475,7 @@
+ */
+ SimpleContainer(final Application application, final ServiceLocator parentLocator) {
+ this.appHandler = new ApplicationHandler(application, new SimpleBinder(), parentLocator);
++ this.scheduler = new ScheduledThreadPoolExecutor(2, new DaemonFactory(TimeoutDispatcher.class));
+ }
+
+ /**
+@@ -393,5 +485,6 @@
+ */
+ SimpleContainer(final Application application) {
+ this.appHandler = new ApplicationHandler(application, new SimpleBinder());
++ this.scheduler = new ScheduledThreadPoolExecutor(2, new DaemonFactory(TimeoutDispatcher.class));
+ }
+ }
+diff -Nru jersey-2.23.2/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java jersey-2.23.2.simple/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java
+--- jersey-2.23.2/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java 2016-08-08 19:11:27.000000000 +0200
++++ jersey-2.23.2.simple/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleServer.java 2016-09-28 13:59:48.889237999 +0200
+@@ -50,5 +50,34 @@
+ */
+ public interface SimpleServer extends Closeable {
+
++ /**
++ * The port the server is listening to for incomming HTTP connections. If the
++ * port is not specified the {@linke org.glassfish.jersey.server.spi.Container.DEFAULT_PORT}
++ * is used.
++ *
++ * @return the port the server is listening on
++ */
+ public int getPort();
++
++ /**
++ * If this is true then very low level I/O operations are logged. Typically this is used
++ * to debug I/O issues such as HTTPS handshakes or performance issues by analysing the
++ * various latencies involved in the HTTP conversation.
++ *
++ * There is a minimal performance penalty if this is enabled and it is perfectly suited
++ * to being enabled in a production environment, at the cost of logging overhead.
++ *
++ * @return true if debug is enabled, false otherwise
++ */
++ public boolean isDebug();
++
++ /**
++ * To enable very low level logging this can be enabled. This goes far beyond logging
++ * issues such as connection establishment of request dispatch, it can trace the TCP
++ * operations latencies involved.
++ *
++ * @param enable if true debug tracing will be enabled
++ */
++ public void setDebug(boolean enable);
++
+ }
+diff -Nru jersey-2.23.2/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleTraceAnalyzer.java jersey-2.23.2.simple/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleTraceAnalyzer.java
+--- jersey-2.23.2/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleTraceAnalyzer.java 1970-01-01 01:00:00.000000000 +0100
++++ jersey-2.23.2.simple/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleTraceAnalyzer.java 2016-09-28 13:59:48.890237947 +0200
+@@ -0,0 +1,177 @@
++package org.glassfish.jersey.simple;
++
++import java.io.PrintWriter;
++import java.io.StringWriter;
++import java.nio.channels.SelectableChannel;
++import java.util.Queue;
++import java.util.concurrent.ConcurrentLinkedQueue;
++import java.util.concurrent.ThreadFactory;
++import java.util.concurrent.atomic.AtomicBoolean;
++import java.util.concurrent.atomic.AtomicLong;
++import java.util.logging.Level;
++import java.util.logging.Logger;
++
++import org.glassfish.jersey.internal.util.ExtendedLogger;
++import org.simpleframework.common.thread.DaemonFactory;
++import org.simpleframework.transport.trace.Trace;
++import org.simpleframework.transport.trace.TraceAnalyzer;
++
++/**
++ * Tracing at a very low level can be performed with a {@link TraceAnalyzer}. This provides much
++ * more useful information than the conventional {@link LoggingFilter} in that it provides
++ * details at a very low level. This is very useful when monitoring performance interactions
++ * at the TCP level between clients and servers.
++ *
++ * Performance overhead for the server is minimal as events are pumped out in batches. The
++ * amount of logging information will increase quite significantly though.
++ *
++ * @author Niall Gallagher
++ */
++public class SimpleTraceAnalyzer implements TraceAnalyzer {
++
++ private static final ExtendedLogger logger = new ExtendedLogger(Logger.getLogger(SimpleTraceAnalyzer.class.getName()), Level.FINEST);
++
++ private final TraceConsumer consumer;
++ private final ThreadFactory factory;
++ private final AtomicBoolean active;
++ private final AtomicLong count;
++
++ public SimpleTraceAnalyzer() {
++ this.factory = new DaemonFactory(TraceConsumer.class);
++ this.consumer = new TraceConsumer();
++ this.active = new AtomicBoolean();
++ this.count = new AtomicLong();
++ }
++
++ public boolean isActive() {
++ return active.get();
++ }
++
++ @Override
++ public Trace attach(SelectableChannel channel) {
++ long sequence = count.getAndIncrement();
++ return new TraceFeeder(channel, sequence);
++ }
++
++ public void start() {
++ if(active.compareAndSet(false, true)) {
++ Thread thread = factory.newThread(consumer);
++ thread.start();
++ }
++ }
++
++ @Override
++ public void stop() {
++ active.set(false);
++ }
++
++ private class TraceConsumer implements Runnable {
++
++ private final Queue queue;
++
++ public TraceConsumer() {
++ this.queue = new ConcurrentLinkedQueue();
++ }
++
++ public void consume(TraceRecord record) {
++ queue.offer(record);
++ }
++
++ public void run() {
++ try {
++ while(active.get()) {
++ Thread.sleep(1000);
++ drain();
++ }
++ } catch(Exception e) {
++ logger.info("Trace analyzer error");
++ } finally {
++ try {
++ drain();
++ } catch(Exception e) {
++ logger.info("Trace analyzer could not drain queue");
++ }
++ active.set(false);
++ }
++
++ }
++
++ private void drain() {
++ while(!queue.isEmpty()) {
++ TraceRecord record = queue.poll();
++
++ if(record != null) {
++ String message = record.toString();
++ logger.info(message);
++ }
++ }
++ }
++ }
++
++ private class TraceFeeder implements Trace {
++
++ private final SelectableChannel channel;
++ private final long sequence;
++
++ public TraceFeeder(SelectableChannel channel, long sequence) {
++ this.sequence = sequence;
++ this.channel = channel;
++ }
++
++ @Override
++ public void trace(Object event) {
++ trace(event, null);
++ }
++
++ @Override
++ public void trace(Object event, Object value) {
++ if(active.get()) {
++ TraceRecord record = new TraceRecord(channel, event, value, sequence);
++ consumer.consume(record);
++ }
++ }
++
++ }
++
++ private class TraceRecord {
++
++ private final SelectableChannel channel;
++ private final String thread;
++ private final Object event;
++ private final Object value;
++ private final long sequence;
++
++ public TraceRecord(SelectableChannel channel, Object event, Object value, long sequence) {
++ this.thread = Thread.currentThread().getName();
++ this.sequence = sequence;
++ this.channel = channel;
++ this.event = event;
++ this.value = value;
++ }
++
++ public String toString() {
++ StringWriter builder = new StringWriter();
++ PrintWriter writer = new PrintWriter(builder);
++
++ writer.print(sequence);
++ writer.print(" ");
++ writer.print(channel);
++ writer.print(" (");
++ writer.print(thread);
++ writer.print("): ");
++ writer.print(event);
++
++ if(value != null) {
++ if(value instanceof Throwable) {
++ writer.print(" -> ");
++ ((Throwable)value).printStackTrace(writer);
++ } else {
++ writer.print(" -> ");
++ writer.print(value);
++ }
++ }
++ writer.close();
++ return builder.toString();
++ }
++ }
++}
+diff -Nru jersey-2.23.2/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java jersey-2.23.2.simple/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java
+--- jersey-2.23.2/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java 2016-08-08 19:11:27.000000000 +0200
++++ jersey-2.23.2.simple/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java 2016-09-28 13:59:48.890237947 +0200
+@@ -94,7 +94,7 @@
+ return DEFAULT_PORT;
+ }
+
+- private volatile Closeable server;
++ private volatile SimpleServer server;
+
+ public UriBuilder getUri() {
+ return UriBuilder.fromUri("http://localhost").port(getPort()).path(CONTEXT);
+@@ -108,6 +108,13 @@
+ LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri);
+ }
+
++ public void startServerNoLoggingFilter(Class... resources) {
++ ResourceConfig config = new ResourceConfig(resources);
++ final URI baseUri = getBaseUri();
++ server = SimpleContainerFactory.create(baseUri, config);
++ LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri);
++ }
++
+ public void startServer(ResourceConfig config) {
+ final URI baseUri = getBaseUri();
+ config.register(LoggingFeature.class);
+@@ -126,6 +133,12 @@
+ return UriBuilder.fromUri("http://localhost/").port(getPort()).build();
+ }
+
++ public void setDebug(boolean enable) {
++ if(server != null) {
++ server.setDebug(enable);
++ }
++ }
++
+ public void stopServer() {
+ try {
+ server.close();
+diff -Nru jersey-2.23.2/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AsyncTest.java jersey-2.23.2.simple/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AsyncTest.java
+--- jersey-2.23.2/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AsyncTest.java 1970-01-01 01:00:00.000000000 +0100
++++ jersey-2.23.2.simple/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AsyncTest.java 2016-09-28 13:59:48.890237947 +0200
+@@ -0,0 +1,193 @@
++/*
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
++ *
++ * Copyright (c) 2013-2015 Oracle and/or its affiliates. All rights reserved.
++ *
++ * The contents of this file are subject to the terms of either the GNU
++ * General Public License Version 2 only ("GPL") or the Common Development
++ * and Distribution License("CDDL") (collectively, the "License"). You
++ * may not use this file except in compliance with the License. You can
++ * obtain a copy of the License at
++ * http://glassfish.java.net/public/CDDL+GPL_1_1.html
++ * or packager/legal/LICENSE.txt. See the License for the specific
++ * language governing permissions and limitations under the License.
++ *
++ * When distributing the software, include this License Header Notice in each
++ * file and include the License file at packager/legal/LICENSE.txt.
++ *
++ * GPL Classpath Exception:
++ * Oracle designates this particular file as subject to the "Classpath"
++ * exception as provided by Oracle in the GPL Version 2 section of the License
++ * file that accompanied this code.
++ *
++ * Modifications:
++ * If applicable, add the following below the License Header, with the fields
++ * enclosed by brackets [] replaced by your own identifying information:
++ * "Portions Copyright [year] [name of copyright owner]"
++ *
++ * Contributor(s):
++ * If you wish your version of this file to be governed by only the CDDL or
++ * only the GPL Version 2, indicate your decision by adding "[Contributor]
++ * elects to include this software in this distribution under the [CDDL or GPL
++ * Version 2] license." If you don't indicate a single choice of license, a
++ * recipient has the option to distribute your version of this file under
++ * either the CDDL, the GPL Version 2 or to extend the choice of license to
++ * its licensees as provided above. However, if you add GPL Version 2 code
++ * and therefore, elected the GPL Version 2 license, then the option applies
++ * only if the new code is made subject to such option by the copyright
++ * holder.
++ */
++package org.glassfish.jersey.simple;
++
++import static org.hamcrest.CoreMatchers.is;
++import static org.junit.Assert.assertEquals;
++import static org.junit.Assert.assertThat;
++
++import java.util.concurrent.ExecutionException;
++import java.util.concurrent.Future;
++import java.util.concurrent.TimeUnit;
++import java.util.concurrent.TimeoutException;
++import java.util.concurrent.atomic.AtomicInteger;
++
++import javax.ws.rs.GET;
++import javax.ws.rs.Path;
++import javax.ws.rs.client.Client;
++import javax.ws.rs.client.ClientBuilder;
++import javax.ws.rs.container.AsyncResponse;
++import javax.ws.rs.container.Suspended;
++import javax.ws.rs.container.TimeoutHandler;
++import javax.ws.rs.core.Response;
++
++import org.junit.After;
++import org.junit.Before;
++import org.junit.Test;
++
++/**
++ * @author Arul Dhesiaseelan (aruld at acm.org)
++ * @author Michal Gajdos
++ */
++public class AsyncTest extends AbstractSimpleServerTester {
++
++ @Path("/async")
++ @SuppressWarnings("VoidMethodAnnotatedWithGET")
++ public static class AsyncResource {
++
++ public static AtomicInteger INVOCATION_COUNT = new AtomicInteger(0);
++
++ @GET
++ public void asyncGet(@Suspended final AsyncResponse asyncResponse) {
++ new Thread(new Runnable() {
++
++ @Override
++ public void run() {
++ final String result = veryExpensiveOperation();
++ asyncResponse.resume(result);
++ }
++
++ private String veryExpensiveOperation() {
++ // ... very expensive operation that typically finishes within 5 seconds, simulated using sleep()
++ try {
++ Thread.sleep(5000);
++ } catch (final InterruptedException e) {
++ // ignore
++ }
++ return "DONE";
++ }
++ }).start();
++ }
++
++ @GET
++ @Path("timeout")
++ public void asyncGetWithTimeout(@Suspended final AsyncResponse asyncResponse) {
++ asyncResponse.setTimeoutHandler(new TimeoutHandler() {
++
++ @Override
++ public void handleTimeout(final AsyncResponse asyncResponse) {
++ asyncResponse.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("Operation time out.")
++ .build());
++ }
++ });
++ asyncResponse.setTimeout(3, TimeUnit.SECONDS);
++
++ new Thread(new Runnable() {
++
++ @Override
++ public void run() {
++ final String result = veryExpensiveOperation();
++ asyncResponse.resume(result);
++ }
++
++ private String veryExpensiveOperation() {
++ // ... very expensive operation that typically finishes within 10 seconds, simulated using sleep()
++ try {
++ Thread.sleep(7000);
++ } catch (final InterruptedException e) {
++ // ignore
++ }
++ return "DONE";
++ }
++ }).start();
++ }
++
++ @GET
++ @Path("multiple-invocations")
++ public void asyncMultipleInvocations(@Suspended final AsyncResponse asyncResponse) {
++ INVOCATION_COUNT.incrementAndGet();
++
++ new Thread(new Runnable() {
++ @Override
++ public void run() {
++ asyncResponse.resume("OK");
++ }
++ }).start();
++ }
++ }
++
++ private Client client;
++
++ @Before
++ public void setUp() throws Exception {
++ startServer(AsyncResource.class);
++ client = ClientBuilder.newClient();
++ }
++
++ @Override
++ @After
++ public void tearDown() {
++ super.tearDown();
++ client = null;
++ }
++
++ @Test
++ public void testAsyncGet() throws ExecutionException, InterruptedException {
++ final Future responseFuture = client.target(getUri().path("/async")).request().async().get();
++ // Request is being processed asynchronously.
++ final Response response = responseFuture.get();
++ // get() waits for the response
++ assertEquals("DONE", response.readEntity(String.class));
++ }
++
++ @Test
++ public void testAsyncGetWithTimeout() throws ExecutionException, InterruptedException, TimeoutException {
++ final Future responseFuture = client.target(getUri().path("/async/timeout")).request().async().get();
++ // Request is being processed asynchronously.
++ final Response response = responseFuture.get();
++
++ // get() waits for the response
++ assertEquals(503, response.getStatus());
++ assertEquals("Operation time out.", response.readEntity(String.class));
++ }
++
++ /**
++ * JERSEY-2616 reproducer. Make sure resource method is only invoked once per one request.
++ */
++ @Test
++ public void testAsyncMultipleInvocations() throws Exception {
++ final Response response = client.target(getUri().path("/async/multiple-invocations")).request().get();
++
++ assertThat(AsyncResource.INVOCATION_COUNT.get(), is(1));
++
++ assertThat(response.getStatus(), is(200));
++ assertThat(response.readEntity(String.class), is("OK"));
++ }
++}
+diff -Nru jersey-2.23.2/containers/simple-http/src/test/java/org/glassfish/jersey/simple/TraceTest.java jersey-2.23.2.simple/containers/simple-http/src/test/java/org/glassfish/jersey/simple/TraceTest.java
+--- jersey-2.23.2/containers/simple-http/src/test/java/org/glassfish/jersey/simple/TraceTest.java 1970-01-01 01:00:00.000000000 +0100
++++ jersey-2.23.2.simple/containers/simple-http/src/test/java/org/glassfish/jersey/simple/TraceTest.java 2016-09-28 13:59:48.890237947 +0200
+@@ -0,0 +1,89 @@
++package org.glassfish.jersey.simple;
++
++import static org.hamcrest.CoreMatchers.is;
++import static org.hamcrest.MatcherAssert.assertThat;
++import static org.junit.Assert.assertEquals;
++import static org.junit.Assert.assertTrue;
++
++import javax.ws.rs.GET;
++import javax.ws.rs.Path;
++import javax.ws.rs.Produces;
++import javax.ws.rs.client.Client;
++import javax.ws.rs.client.ClientBuilder;
++import javax.ws.rs.core.Response;
++
++import org.junit.After;
++import org.junit.Before;
++import org.junit.Test;
++
++public class TraceTest extends AbstractSimpleServerTester {
++
++ @Path("helloworld")
++ public static class HelloWorldResource {
++ public static final String CLICHED_MESSAGE = "Hello World!";
++
++ @GET
++ @Produces("text/plain")
++ public String getHello() {
++ return CLICHED_MESSAGE;
++ }
++ }
++
++ @Path("/users")
++ public class UserResource {
++
++ @Path("/current")
++ @GET
++ @Produces("text/plain")
++ public String getCurrentUser() {
++ return "current user";
++ }
++ }
++
++ private Client client;
++
++ @Before
++ public void setUp() throws Exception {
++ startServerNoLoggingFilter(HelloWorldResource.class, UserResource.class); // disable crude LoggingFilter
++ setDebug(true);
++ client = ClientBuilder.newClient();
++ }
++
++ @Override
++ @After
++ public void tearDown() {
++ super.tearDown();
++ client = null;
++ }
++
++
++ @Test
++ public void testFooBarOptions() {
++ for(int i = 0; i < 100; i++) {
++ Response response = client.target(getUri()).path("helloworld").request().header("Accept", "foo/bar").options();
++ assertEquals(200, response.getStatus());
++ final String allowHeader = response.getHeaderString("Allow");
++ _checkAllowContent(allowHeader);
++ assertEquals(0, response.getLength());
++ assertEquals("foo/bar", response.getMediaType().toString());
++
++ try {
++ Thread.sleep(50);
++ } catch(Exception e) {
++ e.printStackTrace();
++ }
++ }
++ }
++
++ private void _checkAllowContent(final String content) {
++ assertTrue(content.contains("GET"));
++ assertTrue(content.contains("HEAD"));
++ assertTrue(content.contains("OPTIONS"));
++ }
++
++ @Test
++ public void testNoDefaultMethod() {
++ Response response = client.target(getUri()).path("/users").request().options();
++ assertThat(response.getStatus(), is(404));
++ }
++}
+diff -Nru jersey-2.23.2/pom.xml jersey-2.23.2.simple/pom.xml
+--- jersey-2.23.2/pom.xml 2016-08-08 19:11:27.000000000 +0200
++++ jersey-2.23.2.simple/pom.xml 2016-09-28 13:59:48.891237895 +0200
+@@ -1489,7 +1489,17 @@
+
+
+ org.simpleframework
+- simple
++ simple-common
++ ${simple.version}
++
++
++ org.simpleframework
++ simple-http
++ ${simple.version}
++
++
++ org.simpleframework
++ simple-transport
+ ${simple.version}
+
+
+@@ -1941,7 +1951,7 @@
+ 1.0.12
+ 2.4
+ 3.0.1
+- 5.1.4
++ 6.0.1
+ 1.7.12
+ 3.2.3.RELEASE
+ 1.1.0.Final
diff --git a/jersey.spec b/jersey.spec
index b0958a2..376404b 100644
--- a/jersey.spec
+++ b/jersey.spec
@@ -1,8 +1,8 @@
# Use jetty 9.2.14.v20151106
%bcond_with jetty
Name: jersey
-Version: 2.23.1
-Release: 4%{?dist}
+Version: 2.23.2
+Release: 1%{?dist}
Summary: JAX-RS (JSR 311) production quality Reference Implementation
# One file in jersey-core/ is under ASL 2.0 license
License: (CDDL or GPLv2 with exceptions) and ASL 2.0
@@ -13,7 +13,7 @@ Source1: http://www.apache.org/licenses/LICENSE-2.0.txt
# Support fo servlet 3.1 apis
Patch0: jersey-2.17-mvc-jsp-servlet31.patch
-Patch1: jersey-2.23.1-port-to-simple6.patch
+Patch1: jersey-2.23.2-port-to-simple6.patch
Patch2: jersey-2.23.1-port-json-jackson-to-jackson-2.7.patch
@@ -64,6 +64,7 @@ BuildRequires: mvn(org.freemarker:freemarker)
BuildRequires: mvn(org.glassfish:javax.json)
BuildRequires: mvn(org.glassfish:jsonp-jaxrs)
BuildRequires: mvn(org.glassfish.grizzly:grizzly-http-servlet)
+# Use hk2:2.5.0-b05 update when is available "Final" release
BuildRequires: mvn(org.glassfish.hk2:hk2)
BuildRequires: mvn(org.glassfish.hk2:hk2-api)
BuildRequires: mvn(org.glassfish.hk2:hk2-bom:pom:)
@@ -72,8 +73,6 @@ BuildRequires: mvn(org.glassfish.hk2:osgi-resource-locator)
BuildRequires: mvn(org.glassfish.hk2:spring-bridge)
BuildRequires: mvn(org.glassfish.web:javax.el)
BuildRequires: mvn(org.hamcrest:hamcrest-library)
-# org.hibernate:hibernate-validator:5.1.3.Final
-# https://bugzilla.redhat.com/show_bug.cgi?id=1182918
BuildRequires: mvn(org.hibernate:hibernate-validator)
BuildRequires: mvn(org.hibernate:hibernate-validator-cdi)
BuildRequires: mvn(org.jboss.spec.javax.interceptor:jboss-interceptors-api_1.2_spec)
@@ -122,7 +121,8 @@ find . -name "*.class" -print -delete
%patch0 -p1
%patch1 -p1
-%patch2 -p1
+#%% patch2 -p1
+
# Remove repackaged dependencies: guava, atinject
sed -i '/jersey.repackaged/d' \
@@ -179,7 +179,12 @@ sed -i 's/\r//' LICENSE-2.0.txt
%pom_disable_module examples/java8-webapp
%pom_disable_module examples/rx-client-java8-webapp
%pom_disable_module gae-integration incubator
-%pom_disable_module html-json incubator
+
+# org.netbeans.api:org-openide-util-lookup:RELEASE80
+# org.netbeans.html:ko-ws-tyrus:1.0
+# org.netbeans.html:net.java.html.json:1.0
+#%% pom_disable_module html-json incubator
+
# org.codehaus.groovy:groovy-eclipse-compiler:2.9.2-01
%pom_disable_module container-runner-maven-plugin test-framework/maven
@@ -214,6 +219,13 @@ sed -i 's/\r//' LICENSE-2.0.txt
%pom_disable_module moxy media
%pom_remove_dep :jersey-media-moxy bom
+# io.netty:netty-all:4.1.4.Final
+%pom_disable_module netty-connector connectors
+%pom_disable_module netty-http containers
+%pom_remove_dep :jersey-container-netty-http bom
+%pom_disable_module netty test-framework/providers
+%pom_remove_dep :jersey-test-framework-provider-netty test-framework/providers/bundle
+
# Fix asm aId (asm-debug-all)
%pom_xpath_set "pom:dependency[pom:groupId = 'org.ow2.asm']/pom:artifactId" asm-all
%pom_xpath_set "pom:dependency[pom:groupId = 'org.ow2.asm']/pom:artifactId" asm-all core-server
@@ -379,6 +391,9 @@ sed -i "s|Xmx1024m|Xmx512m|" pom.xml
%license LICENSE.html LICENSE.txt LICENSE-2.0.txt etc/config/copyright.txt
%changelog
+* Wed Sep 28 2016 gil cattaneo 2.23.2-1
+- update to 2.23.2
+
* Wed Aug 24 2016 gil cattaneo 2.23.1-4
- jackson 2.7 build fix
diff --git a/sources b/sources
index 418d6b9..4649a7b 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-dc4a417e1291385c0adaac17587fee61 jersey-2.23.1.tar.gz
+a06ff3ffbdd8488f3eb076ee6a0e44e1 jersey-2.23.2.tar.gz