/** * 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. */ package org.apache.cxf.systest.jaxrs; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.cxf.helpers.IOUtils; import org.apache.cxf.jaxrs.client.WebClient; import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase; import org.junit.Ignore; import org.junit.Test; public abstract class AbstractJAXRSContinuationsTest extends AbstractBusClientServerTestBase { @Test public void testDefaultTimeout() throws Exception { WebClient wc = WebClient.create("http://localhost:" + getPort() + getBaseAddress() + "/books/defaulttimeout"); Response r = wc.get(); assertEquals(503, r.getStatus()); } @Test public void testImmediateResume() throws Exception { WebClient wc = WebClient.create("http://localhost:" + getPort() + getBaseAddress() + "/books/resume"); wc.accept("text/plain"); String str = wc.get(String.class); assertEquals("immediateResume", str); } @Test public void testResumeFromFastAppThread() throws Exception { WebClient wc = WebClient.create("http://localhost:" + getPort() + getBaseAddress2() + "/books/resumeFromFastThread"); wc.accept("text/plain"); String str = wc.get(String.class); assertEquals("resumeFromFastThread", str); } @Test public void testNoContent() throws Exception { WebClient wc = WebClient.create("http://localhost:" + getPort() + getBaseAddress() + "/books/nocontent"); wc.accept("text/plain"); Response r = wc.get(Response.class); assertEquals(204, r.getStatus()); } @Test public void testCustomStatusFromInterface() throws Exception { WebClient wc = WebClient.create("http://localhost:" + getPort() + getBaseAddress() + "/books/async/nocontentInterface"); wc.accept("text/plain"); Response r = wc.get(Response.class); assertEquals(206, r.getStatus()); } @Test public void testUnmappedAfterTimeout() throws Exception { WebClient wc = WebClient.create("http://localhost:" + getPort() + getBaseAddress() + "/books/suspend/unmapped"); Response r = wc.get(); assertEquals(500, r.getStatus()); } @Test public void testImmediateResumeSubresource() throws Exception { WebClient wc = WebClient.create("http://localhost:" + getPort() + getBaseAddress() + "/books/subresources/books/resume"); wc.accept("text/plain"); String str = wc.get(String.class); assertEquals("immediateResume", str); } @Test public void testGetBookNotFound() throws Exception { WebClient wc = WebClient.create("http://localhost:" + getPort() + getBaseAddress() + "/books/notfound"); wc.accept("text/plain"); Response r = wc.get(); assertEquals(404, r.getStatus()); } @Test public void testGetBookNotFoundUnmapped() throws Exception { WebClient wc = WebClient.create("http://localhost:" + getPort() + getBaseAddress() + "/books/notfound/unmapped"); wc.accept("text/plain"); Response r = wc.get(); assertEquals(500, r.getStatus()); } @Test public void testGetBookNotFoundUnmappedImmediate() throws Exception { WebClient wc = WebClient.create("http://localhost:" + getPort() + getBaseAddress() + "/books/notfound/unmappedImmediate"); wc.accept("text/plain"); Response r = wc.get(); assertEquals(500, r.getStatus()); } @Test public void testGetBookMappedImmediate() throws Exception { WebClient wc = WebClient.create("http://localhost:" + getPort() + getBaseAddress() + "/books/mappedImmediate"); wc.accept("text/plain"); Response r = wc.get(); assertEquals(401, r.getStatus()); } @Test public void testTimeoutAndCancel() throws Exception { doTestTimeoutAndCancel(getBaseAddress()); } protected void doTestTimeoutAndCancel(String baseAddress) throws Exception { WebClient wc = WebClient.create("http://localhost:" + getPort() + baseAddress + "/books/cancel"); Response r = wc.get(); assertEquals(503, r.getStatus()); String retryAfter = r.getHeaderString(HttpHeaders.RETRY_AFTER); assertNotNull(retryAfter); assertEquals("10", retryAfter); } @Test public void testContinuationWithTimeHandler() throws Exception { doTestContinuation("/books/timeouthandler"); } @Test public void testContinuationWithTimeHandlerResumeOnly() throws Exception { doTestContinuation("/books/timeouthandlerresume"); } @Test public void testContinuation() throws Exception { doTestContinuation("/books"); } @Test public void testContinuationSubresource() throws Exception { doTestContinuation("/books/subresources"); } protected void doTestContinuation(String pathSegment) throws Exception { final String port = getPort(); ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10)); CountDownLatch startSignal = new CountDownLatch(1); CountDownLatch doneSignal = new CountDownLatch(1); List<BookWorker> workers = new ArrayList<>(5); for (int x = 1; x < 6; x++) { workers.add(new BookWorker("http://localhost:" + port + getBaseAddress() + pathSegment + "/" + x, Integer.toString(x), "CXF in Action" + x, startSignal, doneSignal)); } for (BookWorker w : workers) { executor.execute(w); } startSignal.countDown(); doneSignal.await(60, TimeUnit.SECONDS); executor.shutdownNow(); assertEquals("Not all invocations have completed", 0, doneSignal.getCount()); for (BookWorker w : workers) { w.checkError(); } } private void checkBook(String address, String id, String expected) throws Exception { GetMethod get = new GetMethod(address); HttpClient httpclient = new HttpClient(); try { int result = httpclient.executeMethod(get); assertEquals(200, result); assertEquals("Book description for id " + id + " is wrong", expected, IOUtils.toString(get.getResponseBodyAsStream())); } finally { // Release current connection to the connection pool once you are done get.releaseConnection(); } } @Ignore private class BookWorker implements Runnable { private String address; private String id; private String expected; private CountDownLatch startSignal; private CountDownLatch doneSignal; private Exception error; BookWorker(String address, String id, String expected, CountDownLatch startSignal, CountDownLatch doneSignal) { this.address = address; this.id = id; this.expected = expected; this.startSignal = startSignal; this.doneSignal = doneSignal; } public void checkError() throws Exception { if (error != null) { throw error; } } public void run() { try { startSignal.await(); checkBook(address, id, expected); doneSignal.countDown(); } catch (InterruptedException ex) { // ignore } catch (Exception ex) { ex.fillInStackTrace(); error = ex; } } } protected String getBaseAddress() { return "/bookstore"; } protected String getBaseAddress2() { return "/bookstore"; } protected abstract String getPort(); }