Author: dkulp
Date: Fri Jul 31 19:54:22 2009
New Revision: 799723
URL: http://svn.apache.org/viewvc?rev=799723&view=rev
Log:
[CXF-2373] Fix for some JAX-RS fault handling issues
Patch from Eamonn Dwyer applied
Modified:
cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/InFaultChainInitiatorObserver.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java
cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStoreSoapRestImpl.java
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java
Modified:
cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/InFaultChainInitiatorObserver.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/InFaultChainInitiatorObserver.java?rev=799723&r1=799722&r2=799723&view=diff
==============================================================================
---
cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/InFaultChainInitiatorObserver.java
(original)
+++
cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/InFaultChainInitiatorObserver.java
Fri Jul 31 19:54:22 2009
@@ -37,10 +37,13 @@
protected void initializeInterceptors(Exchange ex, PhaseInterceptorChain
chain) {
Endpoint e = ex.get(Endpoint.class);
Client c = ex.get(Client.class);
+ InterceptorProvider ip = ex.get(InterceptorProvider.class);
chain.add(getBus().getInFaultInterceptors());
if (c != null) {
chain.add(c.getInFaultInterceptors());
+ } else if (ip != null) {
+ chain.add(ip.getInFaultInterceptors());
}
chain.add(e.getService().getInFaultInterceptors());
chain.add(e.getInFaultInterceptors());
Modified:
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java?rev=799723&r1=799722&r2=799723&view=diff
==============================================================================
---
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java
(original)
+++
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java
Fri Jul 31 19:54:22 2009
@@ -291,13 +291,22 @@
currentBuilder = new UriBuilderImpl(uri);
}
- protected ResponseBuilder setResponseBuilder(HttpURLConnection conn,
Message inMessage) throws Throwable {
-
+ protected ResponseBuilder setResponseBuilder(HttpURLConnection conn,
Exchange exchange) throws Throwable {
+ Message inMessage = exchange.getInMessage();
if (conn == null) {
throw new WebApplicationException();
}
-
- int status = conn.getResponseCode();
+ Integer responseCode = (Integer)exchange.get(Message.RESPONSE_CODE);
+ if (responseCode == null) {
+ //Invocation was never made to server, something stopped the
outbound
+ //interceptor chain, we dont have a response code.
+ //Do not call conn.getResponseCode() as that will
+ //result in a call to the server when we have already decided not
to.
+ //Throw an exception if we have one
+ Exception ex =
exchange.getOutMessage().getContent(Exception.class);
+ throw ex;
+ }
+ int status = responseCode.intValue(); //conn.getResponseCode();
responseBuilder = Response.status(status);
for (Map.Entry<String, List<String>> entry :
conn.getHeaderFields().entrySet()) {
if (null == entry.getKey()) {
Modified:
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java?rev=799723&r1=799722&r2=799723&view=diff
==============================================================================
---
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
(original)
+++
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
Fri Jul 31 19:54:22 2009
@@ -43,8 +43,10 @@
import org.apache.cxf.common.i18n.BundleUtils;
import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor;
import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.interceptor.InterceptorProvider;
import org.apache.cxf.jaxrs.impl.MetadataMap;
import org.apache.cxf.jaxrs.model.ClassResourceInfo;
import org.apache.cxf.jaxrs.model.OperationResourceInfo;
@@ -199,25 +201,41 @@
return index;
}
- private static void checkResponse(Method m, Response r, Message message)
throws Throwable {
-
+ private void checkResponse(Method m, Response r, Message inMessage) throws
Throwable {
+ Throwable t = null;
int status = r.getStatus();
if (status >= 400) {
-
if (m.getReturnType() == Response.class &&
m.getExceptionTypes().length == 0) {
return;
- }
-
- ResponseExceptionMapper<?> mapper = findExceptionMapper(m,
message);
+ }
+ ResponseExceptionMapper<?> mapper = findExceptionMapper(m,
inMessage);
if (mapper != null) {
- Throwable t = mapper.fromResponse(r);
+ t = mapper.fromResponse(r);
if (t != null) {
throw t;
}
+ }
+
+ if (t == null) {
+ t = new WebApplicationException(r);
+ }
+
+
+ if (inMessage.getExchange().get(Message.RESPONSE_CODE) == null) {
+ throw t;
}
- throw new WebApplicationException(r);
+ Endpoint ep = inMessage.getExchange().get(Endpoint.class);
+ inMessage.getExchange().put(InterceptorProvider.class,
getConfiguration());
+ inMessage.setContent(Exception.class, new Fault(t));
+ inMessage.getInterceptorChain().abort();
+ if (ep.getInFaultObserver() != null) {
+ ep.getInFaultObserver().onMessage(inMessage);
+ }
+
+ throw t;
+
}
}
@@ -392,7 +410,7 @@
m.getInterceptorChain().add(new BodyWriter());
}
- // execute chain
+ // execute chain
try {
m.getInterceptorChain().doIntercept(m);
} catch (Throwable ex) {
@@ -407,7 +425,7 @@
protected Object handleResponse(HttpURLConnection connect, Message
outMessage, OperationResourceInfo ori)
throws Throwable {
- Response r = setResponseBuilder(connect,
outMessage.getExchange().getInMessage()).clone().build();
+ Response r = setResponseBuilder(connect,
outMessage.getExchange()).clone().build();
Method method = ori.getMethodToInvoke();
checkResponse(method, r, outMessage);
if (method.getReturnType() == Void.class) {
Modified:
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java?rev=799723&r1=799722&r2=799723&view=diff
==============================================================================
---
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java
(original)
+++
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java
Fri Jul 31 19:54:22 2009
@@ -538,7 +538,7 @@
protected Response handleResponse(HttpURLConnection conn, Message
outMessage, Class<?> responseClass) {
try {
- ResponseBuilder rb = setResponseBuilder(conn,
outMessage.getExchange().getInMessage()).clone();
+ ResponseBuilder rb = setResponseBuilder(conn,
outMessage.getExchange()).clone();
Response currentResponse = rb.clone().build();
Object entity = readBody(currentResponse, conn, outMessage,
responseClass, responseClass,
Modified:
cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java?rev=799723&r1=799722&r2=799723&view=diff
==============================================================================
---
cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java
(original)
+++
cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java
Fri Jul 31 19:54:22 2009
@@ -1422,6 +1422,9 @@
) throws IOException {
int responseCode = connection.getResponseCode();
+ if ((message != null) && (message.getExchange() != null)) {
+ message.getExchange().put(Message.RESPONSE_CODE, responseCode);
+ }
// Process Redirects first.
switch(responseCode) {
@@ -2044,6 +2047,9 @@
}
protected void handleResponseInternal() throws IOException {
int responseCode = connection.getResponseCode();
+ if ((outMessage != null) && (outMessage.getExchange() != null)) {
+ outMessage.getExchange().put(Message.RESPONSE_CODE,
responseCode);
+ }
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Response Code: "
@@ -2137,6 +2143,7 @@
incomingObserver.onMessage(inMessage);
+
}
Modified:
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStoreSoapRestImpl.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStoreSoapRestImpl.java?rev=799723&r1=799722&r2=799723&view=diff
==============================================================================
---
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStoreSoapRestImpl.java
(original)
+++
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStoreSoapRestImpl.java
Fri Jul 31 19:54:22 2009
@@ -77,7 +77,15 @@
throw new RuntimeException();
}
}
- Response r = Response.status(404).header("BOOK-HEADER",
+ int returnCode = 404;
+ if (id == 321) {
+ returnCode = 525;
+ } else if (id == 322) {
+ BookNotFoundDetails details = new BookNotFoundDetails();
+ details.setId(id);
+ throw new BookNotFoundFault(details);
+ }
+ Response r = Response.status(returnCode).header("BOOK-HEADER",
"No Book with id " + id + " is available").build();
throw new WebApplicationException(r);
}
Modified:
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java?rev=799723&r1=799722&r2=799723&view=diff
==============================================================================
---
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java
(original)
+++
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java
Fri Jul 31 19:54:22 2009
@@ -412,10 +412,74 @@
bean.setFeatures(features);
BookStoreJaxrsJaxws proxy = (BookStoreJaxrsJaxws)bean.create();
Book b = proxy.getBook(new Long("123"));
- assertTrue("Interceptor not invoked",
testFeature.handleMessageCalled());
+ assertTrue("Out Interceptor not invoked",
testFeature.handleMessageOnOutInterceptorCalled());
+ assertTrue("In Interceptor not invoked",
testFeature.handleMessageOnInInterceptorCalled());
assertEquals(123, b.getId());
assertEquals("CXF in Action", b.getName());
}
+
+ @Test
+ public void testServerFaultInInterceptor() throws Exception {
+ //testing faults created by server handled correctly
+ serverFaultInInterceptorTest("321");
+ //999 causes error code of 404, 404 has a different code path so need
to test too
+ serverFaultInInterceptorTest("999");
+ //322 causes a checked exception to be thrown so need to
+ serverFaultInInterceptorTest("322");
+ }
+
+ @Test
+ public void testClientFaultOutInterceptor() throws Exception {
+ //testing faults created by client out interceptor chain handled
correctly
+ String baseAddress = "http://localhost:9092/test/services/rest";
+ JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
+ bean.setAddress(baseAddress);
+ bean.setResourceClass(BookStoreJaxrsJaxws.class);
+ final boolean addBadOutInterceptor = true;
+ TestFeature testFeature = new TestFeature(addBadOutInterceptor);
+ List<AbstractFeature> features = new ArrayList<AbstractFeature>();
+ features.add((AbstractFeature)testFeature);
+ bean.setFeatures(features);
+ BookStoreJaxrsJaxws proxy = (BookStoreJaxrsJaxws)bean.create();
+ try {
+ //321 is special case - causes error code of 525
+ proxy.getBook(new Long("123"));
+ fail("Method should have thrown an exception");
+ } catch (Exception e) {
+ assertTrue("Out Interceptor not invoked",
testFeature.handleMessageOnOutInterceptorCalled());
+ assertTrue("In Interceptor not invoked",
!testFeature.handleMessageOnInInterceptorCalled());
+ assertTrue("Wrong exception caught", "fault from bad
interceptor".equals(e.getMessage()));
+ assertTrue("Client In Fault In Interceptor was invoked",
+ !testFeature.faultInInterceptorCalled());
+ }
+ }
+
+ private void serverFaultInInterceptorTest(String param) {
+ String baseAddress = "http://localhost:9092/test/services/rest";
+ JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
+ bean.setAddress(baseAddress);
+ bean.setResourceClass(BookStoreJaxrsJaxws.class);
+ TestFeature testFeature = new TestFeature();
+ List<AbstractFeature> features = new ArrayList<AbstractFeature>();
+ features.add((AbstractFeature)testFeature);
+ bean.setFeatures(features);
+ BookStoreJaxrsJaxws proxy = (BookStoreJaxrsJaxws)bean.create();
+ try {
+ //321 is special case - causes error code of 525
+ proxy.getBook(new Long(param));
+ fail("Method should have thrown an exception");
+ } catch (Exception e) {
+ assertTrue("Out Interceptor not invoked",
testFeature.handleMessageOnOutInterceptorCalled());
+ if ("322".equals(param)) {
+ //In interecptors not called when checked exception thrown
from server
+ assertTrue("In Interceptor not invoked",
testFeature.handleMessageOnInInterceptorCalled());
+ } else {
+ assertTrue("In Interceptor not invoked",
!testFeature.handleMessageOnInInterceptorCalled());
+ }
+ assertTrue("Client In Fault In Interceptor not invoked",
+ testFeature.faultInInterceptorCalled());
+ }
+ }
private String getStringFromInputStream(InputStream in) throws Exception {
CachedOutputStream bos = new CachedOutputStream();
@@ -483,27 +547,52 @@
@Ignore
public class TestFeature extends AbstractFeature {
- private TestInterceptor testInterceptor;
+ private TestOutInterceptor testOutInterceptor;
+ private TestInInterceptor testInInterceptor;
+ private TestFaultInInterceptor testFaultInInterceptor;
+ private boolean addBadOutInterceptor;
+
+ public TestFeature() {
+ }
+
+ public TestFeature(boolean addBadOutInterceptor) {
+ this.addBadOutInterceptor = addBadOutInterceptor;
+ }
@Override
protected void initializeProvider(InterceptorProvider provider, Bus
bus) {
- testInterceptor = new TestInterceptor();
- provider.getOutInterceptors().add(testInterceptor);
+ testOutInterceptor = new TestOutInterceptor(addBadOutInterceptor);
+ testInInterceptor = new TestInInterceptor();
+ testFaultInInterceptor = new TestFaultInInterceptor();
+ provider.getOutInterceptors().add(testOutInterceptor);
+ provider.getInInterceptors().add(testInInterceptor);
+ provider.getInFaultInterceptors().add(testFaultInInterceptor);
+
+
}
- protected boolean handleMessageCalled() {
- return testInterceptor.handleMessageCalled();
+ protected boolean handleMessageOnOutInterceptorCalled() {
+ return testOutInterceptor.handleMessageCalled();
+ }
+
+ protected boolean handleMessageOnInInterceptorCalled() {
+ return testInInterceptor.handleMessageCalled();
+ }
+
+ protected boolean faultInInterceptorCalled() {
+ return testFaultInInterceptor.handleMessageCalled();
}
}
@Ignore
- public class TestInterceptor extends AbstractPhaseInterceptor<Message> {
+ public class TestInInterceptor extends AbstractPhaseInterceptor<Message> {
private boolean handleMessageCalled;
- public TestInterceptor() {
+
+ public TestInInterceptor() {
this(Phase.PRE_STREAM);
}
- public TestInterceptor(String s) {
+ public TestInInterceptor(String s) {
super(Phase.PRE_STREAM);
}
@@ -517,4 +606,56 @@
}
}
+
+ @Ignore
+ public class TestOutInterceptor extends AbstractPhaseInterceptor<Message> {
+ private boolean handleMessageCalled;
+ private boolean isBadOutInterceptor;
+
+
+ public TestOutInterceptor(boolean isBadOutInterceptor) {
+ this(Phase.PRE_MARSHAL);
+ this.isBadOutInterceptor = isBadOutInterceptor;
+ }
+
+ public TestOutInterceptor(String s) {
+ super(Phase.PRE_MARSHAL);
+
+ }
+
+ public void handleMessage(Message message) throws Fault {
+ handleMessageCalled = true;
+ if (isBadOutInterceptor) {
+ throw new Fault(new Exception("fault from bad interceptor"));
+ }
+ }
+
+ protected boolean handleMessageCalled() {
+ return handleMessageCalled;
+ }
+
+ }
+
+ @Ignore
+ public class TestFaultInInterceptor extends
AbstractPhaseInterceptor<Message> {
+ private boolean handleMessageCalled;
+ public TestFaultInInterceptor() {
+ this(Phase.PRE_STREAM);
+ }
+
+ public TestFaultInInterceptor(String s) {
+ super(Phase.PRE_STREAM);
+
+ }
+
+ public void handleMessage(Message message) throws Fault {
+ handleMessageCalled = true;
+ }
+
+ protected boolean handleMessageCalled() {
+ return handleMessageCalled;
+ }
+
+ }
+
}