You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by re...@apache.org on 2021/11/10 02:45:59 UTC
[cxf] 01/02: CXF-8616: Calling oneway methods using async client
hangs response indefinitely (#872)
This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch 3.3.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
commit 2303b1077181cf08b10f86fb219174def87e1478
Author: Andriy Redko <dr...@gmail.com>
AuthorDate: Tue Nov 9 17:15:20 2021 -0500
CXF-8616: Calling oneway methods using async client hangs response indefinitely (#872)
(cherry picked from commit b2eafdee7243776527531cfdeec2f82980424783)
(cherry picked from commit fc916e199db82f3564bf97490fd529c143ffe440)
# Conflicts:
# systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSAsyncClientTest.java
# systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
---
.../main/java/org/apache/cxf/message/Message.java | 7 ++
.../apache/cxf/jaxrs/client/AbstractClient.java | 2 +
.../org/apache/cxf/transport/http/HTTPConduit.java | 7 +-
.../org/apache/cxf/systest/jaxrs/BookStore.java | 5 ++
.../cxf/systest/jaxrs/JAXRSAsyncClientTest.java | 82 +++++++++++++++++++--
.../systest/jaxrs/JAXRSClientServerBookTest.java | 86 +++++++++++-----------
6 files changed, 137 insertions(+), 52 deletions(-)
diff --git a/core/src/main/java/org/apache/cxf/message/Message.java b/core/src/main/java/org/apache/cxf/message/Message.java
index bcb8e04..5a74b61 100644
--- a/core/src/main/java/org/apache/cxf/message/Message.java
+++ b/core/src/main/java/org/apache/cxf/message/Message.java
@@ -92,6 +92,13 @@ public interface Message extends StringMap {
* Default value is true
*/
String PROCESS_202_RESPONSE_ONEWAY_OR_PARTIAL = "org.apache.cxf.transport.process202Response";
+
+ /**
+ * Boolean property specifying if 202 response is partial/oneway response, should it be
+ * propagated down to message observers or not.
+ * Default value is false.
+ */
+ String PROPAGATE_202_RESPONSE_ONEWAY_OR_PARTIAL = "org.apache.cxf.transport.propagate202Response";
/**
* Boolean property specifying if the thread which runs a request is
diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java
index 511dba4..78c884b 100644
--- a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java
+++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java
@@ -978,6 +978,8 @@ public abstract class AbstractClient implements Client {
}
protected void setSupportOnewayResponseProperty(Message outMessage) {
+ // Do propagate the response down to observer chain
+ outMessage.put(Message.PROPAGATE_202_RESPONSE_ONEWAY_OR_PARTIAL, true);
if (!outMessage.getExchange().isOneWay()) {
outMessage.put(Message.PROCESS_ONEWAY_RESPONSE, true);
}
diff --git a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java
index 8e3b132..577b435 100644
--- a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java
+++ b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java
@@ -1660,8 +1660,13 @@ public abstract class HTTPConduit
}
}
exchange.put("IN_CHAIN_COMPLETE", Boolean.TRUE);
-
+
exchange.setInMessage(inMessage);
+ if (MessageUtils.getContextualBoolean(outMessage,
+ Message.PROPAGATE_202_RESPONSE_ONEWAY_OR_PARTIAL, false)) {
+ incomingObserver.onMessage(inMessage);
+ }
+
return;
}
} else {
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java
index e601712..1d8fdfb 100644
--- a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java
@@ -1544,6 +1544,11 @@ public class BookStore {
}
@POST
+ @Path("/no-content")
+ public void noContent() {
+ }
+
+ @POST
@Path("/books/customstatus")
@Produces("application/xml")
@Consumes("text/xml")
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSAsyncClientTest.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSAsyncClientTest.java
index c8341c9..afe5f68 100644
--- a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSAsyncClientTest.java
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSAsyncClientTest.java
@@ -26,6 +26,7 @@ import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@@ -52,6 +53,7 @@ import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
import javax.xml.ws.Holder;
import org.apache.cxf.jaxrs.client.ClientConfiguration;
@@ -68,6 +70,7 @@ import org.junit.Test;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -477,9 +480,73 @@ public class JAXRSAsyncClientTest extends AbstractBusClientServerTestBase {
assertThat(response.getStatus(), equalTo(404));
}
}
+
+ @Test
+ public void testNettyClientGet() throws Exception {
+ final String address = "http://localhost:" + PORT + "/bookstore/books/wildcard";
+
+ JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
+ bean.setTransportId(NettyHttpTransportFactory.DEFAULT_NAMESPACES.get(0));
+ bean.setAddress(address);
+
+ WebClient webClient = bean.createWebClient();
+
+ try (Response response = webClient
+ .to(address, false)
+ .accept("text/plain")
+ .async()
+ .get()
+ .get(10, TimeUnit.SECONDS)) {
+ assertThat(response.getStatus(), equalTo(200));
+ } finally {
+ webClient.close();
+ }
+ }
- private WebClient createWebClient(String address) {
- return WebClient.create(address);
+ @Test
+ public void testNettyClientDeleteWithBody() throws Exception {
+ final String address = "http://localhost:" + PORT + "/bookstore/deletebody";
+
+ JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
+ bean.setTransportId(NettyHttpTransportFactory.DEFAULT_NAMESPACES.get(0));
+ bean.setAddress(address);
+
+ WebClient webClient = bean.createWebClient();
+
+ try {
+ Book book = webClient
+ .to(address, false)
+ .accept("application/xml")
+ .async()
+ .method("DELETE", Entity.entity(new Book("Delete", 123L), "application/xml"), Book.class)
+ .get(20, TimeUnit.SECONDS);
+ assertEquals("Delete", book.getName());
+ } finally {
+ webClient.close();
+ }
+ }
+
+ @Test
+ public void testBookNoContent() throws Exception {
+ final String address = "http://localhost:" + PORT + "/bookstore/no-content";
+ WebClient client = createWebClient(address);
+ Response r = client.type("*/*").async().post(null).get();
+ assertEquals(204, r.getStatus());
+ assertThat(r.readEntity(String.class), equalTo(""));
+ }
+
+ @Test
+ public void testBookOneway() throws Exception {
+ final String address = "http://localhost:" + PORT + "/bookstore/oneway";
+ WebClient client = createWebClient(address, new TestResponseFilter());
+ Response r = client.type("*/*").async().post(null).get();
+ assertEquals(202, r.getStatus());
+ assertThat(r.getEntity(), is(nullValue()));
+ assertThat(r.getHeaderString("X-Filter"), equalTo("true"));
+ }
+
+ private WebClient createWebClient(String address, Object ... providers) {
+ return WebClient.create(address, Arrays.asList(providers));
}
private InvocationCallback<Object> createCallback(final Holder<Object> holder) {
@@ -512,8 +579,8 @@ public class JAXRSAsyncClientTest extends AbstractBusClientServerTestBase {
throw new RuntimeException();
}
-
}
+
@Consumes("application/xml")
private static class FaultyBookReader implements MessageBodyReader<Book> {
@@ -528,19 +595,18 @@ public class JAXRSAsyncClientTest extends AbstractBusClientServerTestBase {
WebApplicationException {
throw new RuntimeException();
}
-
-
}
-
+
+ @Provider
public static class TestResponseFilter implements ClientResponseFilter {
@Override
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext)
throws IOException {
-
+ responseContext.getHeaders().add("X-Filter", "true");
}
-
}
+
private static class GenericInvocationCallback<T> implements InvocationCallback<T> {
private Object result;
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
index f4ccdd0..acf30d7 100644
--- a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
@@ -46,6 +46,9 @@ import javax.ws.rs.ServerErrorException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientResponseContext;
+import javax.ws.rs.client.ClientResponseFilter;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.ResponseProcessingException;
import javax.ws.rs.client.WebTarget;
@@ -57,6 +60,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Variant;
+import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
@@ -95,12 +99,14 @@ import org.apache.http.util.EntityUtils;
import org.junit.BeforeClass;
import org.junit.Test;
+import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -112,8 +118,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
@BeforeClass
public static void startServers() throws Exception {
AbstractResourceInfo.clearAllMaps();
- assertTrue("server did not launch correctly",
- launchServer(BookServer.class, true));
+ assertTrue("server did not launch correctly", launchServer(BookServer.class, true));
createStaticBus();
}
@@ -358,7 +363,6 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
String address = "http://localhost:" + PORT + "/bookstore/customresponse";
WebClient wc = WebClient.create(address);
Response r = wc.accept("application/xml").get(Response.class);
-
r.bufferEntity();
String bookStr = r.readEntity(String.class);
@@ -437,7 +441,6 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
assertEquals(123L, book.getId());
}
-
@Test
public void testGetIntroChapterFromSelectedBook() {
String address = "http://localhost:" + PORT + "/bookstore/books(id=le=123)/chapter";
@@ -481,8 +484,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
@Test
public void testProxyWrongAddress() throws Exception {
- BookStore store = JAXRSClientFactory.create("http://localhost:" + PORT2 + "/wrongaddress",
- BookStore.class);
+ BookStore store = JAXRSClientFactory.create("http://localhost:" + PORT2 + "/wrongaddress", BookStore.class);
try {
store.getBook("123");
fail("ClientException expected");
@@ -564,7 +566,6 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
MultivaluedMap<String, Object> headers = wc.getResponse().getMetadata();
assertEquals("123", headers.getFirst("BookId"));
assertEquals(MultivaluedMap.class.getName(), headers.getFirst("MAP-NAME"));
-
assertNotNull(headers.getFirst("Date"));
wc.header("PLAIN-MAP", "true");
@@ -574,7 +575,6 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
headers = wc.getResponse().getMetadata();
assertEquals("321", headers.getFirst("BookId"));
assertEquals(Map.class.getName(), headers.getFirst("MAP-NAME"));
-
assertNotNull(headers.getFirst("Date"));
}
@@ -675,8 +675,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
@Test
public void testPostCollectionGetBooksWebClient() throws Exception {
- String endpointAddress =
- "http://localhost:" + PORT + "/bookstore/collections3";
+ String endpointAddress = "http://localhost:" + PORT + "/bookstore/collections3";
WebClient wc = WebClient.create(endpointAddress);
wc.accept("application/xml").type("application/xml");
Book b1 = new Book("CXF in Action", 123L);
@@ -692,8 +691,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
@Test
public void testPostCollectionGenericEntityWebClient() throws Exception {
- String endpointAddress =
- "http://localhost:" + PORT + "/bookstore/collections3";
+ String endpointAddress = "http://localhost:" + PORT + "/bookstore/collections3";
WebClient wc = WebClient.create(endpointAddress);
wc.accept("application/xml").type("application/xml");
Book b1 = new Book("CXF in Action", 123L);
@@ -713,8 +711,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
@Test
public void testPostGetCollectionGenericEntityAndType() throws Exception {
- String endpointAddress =
- "http://localhost:" + PORT + "/bookstore/collections";
+ String endpointAddress = "http://localhost:" + PORT + "/bookstore/collections";
WebClient wc = WebClient.create(endpointAddress);
wc.accept("application/xml").type("application/xml");
Book b1 = new Book("CXF in Action", 123L);
@@ -745,8 +742,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
@Test
public void testPostCollectionOfBooksWebClient() throws Exception {
- String endpointAddress =
- "http://localhost:" + PORT + "/bookstore/collections";
+ String endpointAddress = "http://localhost:" + PORT + "/bookstore/collections";
WebClient wc = WebClient.create(endpointAddress);
wc.accept("application/xml").type("application/xml");
Book b1 = new Book("CXF in Action", 123L);
@@ -779,8 +775,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
@Test
public void testPostObjectGetCollection() throws Exception {
- String endpointAddress =
- "http://localhost:" + PORT + "/bookstore/collectionBook";
+ String endpointAddress = "http://localhost:" + PORT + "/bookstore/collectionBook";
WebClient wc = WebClient.create(endpointAddress);
wc.accept("application/xml").type("application/xml");
Book b1 = new Book("Book", 666L);
@@ -794,8 +789,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
@Test
public void testCaching() throws Exception {
- String endpointAddress =
- "http://localhost:" + PORT + "/bookstore/books/response/123";
+ String endpointAddress = "http://localhost:" + PORT + "/bookstore/books/response/123";
// Add the CacheControlFeature to cache books returned by the service on the client side
CacheControlFeature cacheControlFeature = new CacheControlFeature();
@@ -834,8 +828,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
@Test
public void testCachingExpires() throws Exception {
- String endpointAddress =
- "http://localhost:" + PORT + "/bookstore/books/response2/123";
+ String endpointAddress = "http://localhost:" + PORT + "/bookstore/books/response2/123";
// Add the CacheControlFeature to cache books returned by the service on the client side
CacheControlFeature cacheControlFeature = new CacheControlFeature();
@@ -876,8 +869,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
@Test
public void testCachingExpiresUsingETag() throws Exception {
- String endpointAddress =
- "http://localhost:" + PORT + "/bookstore/books/response3/123";
+ String endpointAddress = "http://localhost:" + PORT + "/bookstore/books/response3/123";
// Add the CacheControlFeature to cache books returned by the service on the client side
CacheControlFeature cacheControlFeature = new CacheControlFeature();
@@ -924,6 +916,16 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
assertEquals(202, r.getStatus());
assertFalse(r.getHeaders().isEmpty());
}
+
+ @Test
+ public void testOnewayWebClientWithResponseFilter() throws Exception {
+ final ClientResponseFilter filter = new TestClientResponseFilter();
+ WebClient client = WebClient.create("http://localhost:" + PORT + "/bookstore/oneway", Arrays.asList(filter));
+ Response r = client.header("OnewayRequest", "true").post(null);
+ assertEquals(202, r.getStatus());
+ assertFalse(r.getHeaders().isEmpty());
+ assertThat(r.getHeaderString("X-Filter"), equalTo("true"));
+ }
@Test
public void testOnewayWebClient2() throws Exception {
@@ -975,8 +977,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
@Test
public void testBookWithSpaceProxyNonEncodedSemicolon() throws Exception {
- BookStore store = JAXRSClientFactory.create("http://localhost:" + PORT,
- BookStore.class);
+ BookStore store = JAXRSClientFactory.create("http://localhost:" + PORT, BookStore.class);
Book book = store.getBookWithSemicolon("123;", "custom;:header");
assertEquals(123L, book.getId());
assertEquals("CXF in Action;", book.getName());
@@ -996,9 +997,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
List<Object> providers = new LinkedList<>();
providers.add(new BookServer.NotReturnedExceptionMapper());
providers.add(new BookServer.NotFoundExceptionMapper());
- BookStore store = JAXRSClientFactory.create("http://localhost:" + PORT,
- BookStore.class,
- providers);
+ BookStore store = JAXRSClientFactory.create("http://localhost:" + PORT, BookStore.class, providers);
try {
store.getBookWithExceptions(true);
fail();
@@ -1015,8 +1014,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
@Test
public void testBookWithExceptionsNoMapper() throws Exception {
- BookStore store = JAXRSClientFactory.create("http://localhost:" + PORT,
- BookStore.class);
+ BookStore store = JAXRSClientFactory.create("http://localhost:" + PORT, BookStore.class);
try {
store.getBookWithExceptions(true);
fail();
@@ -1030,9 +1028,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
List<Object> providers = new LinkedList<>();
providers.add(new BookServer.NotReturnedExceptionMapper());
providers.add(BookServer.NotFoundExceptionMapper.class);
- BookStore store = JAXRSClientFactory.create("http://localhost:" + PORT,
- BookStore.class,
- providers);
+ BookStore store = JAXRSClientFactory.create("http://localhost:" + PORT, BookStore.class, providers);
try {
store.getBookWithExceptions2(true);
fail();
@@ -1245,7 +1241,6 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
@Test
public void testAddBookProxyResponse() {
Book b = new Book("CXF rocks", 123L);
-
BookStore store = JAXRSClientFactory.create("http://localhost:" + PORT, BookStore.class);
Response r = store.addBook(b);
assertNotNull(r);
@@ -1279,15 +1274,12 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
@Test
public void testGetJAXBElementXmlRootBookCollection() throws Exception {
- BookStore store = JAXRSClientFactory.create("http://localhost:" + PORT,
- BookStore.class);
+ BookStore store = JAXRSClientFactory.create("http://localhost:" + PORT, BookStore.class);
Book b1 = new Book("CXF in Action", 123L);
Book b2 = new Book("CXF Rocks", 124L);
List<JAXBElement<Book>> books = new ArrayList<>();
- books.add(new JAXBElement<Book>(new QName("bookRootElement"),
- Book.class, b1));
- books.add(new JAXBElement<Book>(new QName("bookRootElement"),
- Book.class, b2));
+ books.add(new JAXBElement<Book>(new QName("bookRootElement"), Book.class, b1));
+ books.add(new JAXBElement<Book>(new QName("bookRootElement"), Book.class, b2));
List<JAXBElement<Book>> books2 = store.getJAXBElementBookXmlRootCollection(books);
assertNotNull(books2);
assertNotSame(books, books2);
@@ -1301,8 +1293,7 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
}
@Test
public void testGetJAXBElementXmlRootBookCollectionWebClient() throws Exception {
- WebClient store = WebClient.create("http://localhost:" + PORT
- + "/bookstore/jaxbelementxmlrootcollections");
+ WebClient store = WebClient.create("http://localhost:" + PORT + "/bookstore/jaxbelementxmlrootcollections");
Book b1 = new Book("CXF in Action", 123L);
Book b2 = new Book("CXF Rocks", 124L);
List<Book> books = new ArrayList<>();
@@ -2992,4 +2983,13 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase {
private String getStringFromInputStream(InputStream in) throws Exception {
return IOUtils.toString(in);
}
+
+ @Provider
+ private static class TestClientResponseFilter implements ClientResponseFilter {
+ @Override
+ public void filter(ClientRequestContext requestContext,
+ ClientResponseContext responseContext) throws IOException {
+ responseContext.getHeaders().add("X-Filter", "true");
+ }
+ }
}