Added FaultResolver to client.

Added getSoapFaultStringOrReason() to SoapFault.
This commit is contained in:
Arjen Poutsma
2007-01-14 20:05:46 +00:00
parent 2faa71f2f3
commit 6ba5576c95
21 changed files with 258 additions and 19 deletions

View File

@@ -62,4 +62,9 @@ public interface WebServiceMessage {
*/
boolean hasFault();
/**
* Returns the fault reason message, if any. Returns <code>null</code> when no fault is present.
*/
String getFaultReason();
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2007 the original author or authors.
*
* Licensed 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.springframework.ws.client.core;
import org.springframework.ws.WebServiceMessage;
/**
* Defines the interface for objects than can resolve received {@link org.springframework.ws.WebServiceMessage}.
*
* @author Arjen Poutsma
*/
public interface FaultResolver {
/**
* Try to resolve the given fault message that got received.
*
* @param message the fault message
*/
void resolveFault(WebServiceMessage message);
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2007 the original author or authors.
*
* Licensed 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.springframework.ws.client.core;
import org.springframework.ws.WebServiceMessage;
/**
* Simple fault resolver that simply throws a {@link WebServiceFaultException} when a fault occurs.
*
* @author Arjen Poutsma
* @see WebServiceFaultException
*/
public class SimpleFaultResolver implements FaultResolver {
/**
* Throws a new <code>WebServiceFaultException</code>.
*/
public void resolveFault(WebServiceMessage message) {
throw new WebServiceFaultException(message.getFaultReason());
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2007 the original author or authors.
*
* Licensed 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.springframework.ws.client.core;
import org.springframework.ws.client.WebServiceClientException;
/**
* Thrown by <code>SimpleFaultResolver</code> when the response message has a fault.
*
* @author Arjen Poutsma
*/
public class WebServiceFaultException extends WebServiceClientException {
public WebServiceFaultException(String msg) {
super(msg);
}
public WebServiceFaultException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -24,6 +24,7 @@ import javax.xml.transform.TransformerException;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.client.WebServiceClientException;
@@ -37,6 +38,8 @@ import org.springframework.ws.transport.WebServiceMessageSender;
* <p/>
* Code using this class need only implement callback interfaces, provide {@link Source} objects to read data from, or
* use the pluggable {@link Marshaller} support.
* <p/>
* This template uses a {@link SimpleFaultResolver} to handle responses that contain faults.
*
* @author Arjen Poutsma
*/
@@ -46,6 +49,8 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
private Unmarshaller unmarshaller;
private FaultResolver faultResolver = new SimpleFaultResolver();
/**
* Creates a new <code>WebServiceTemplate</code>.
* <p/>
@@ -97,6 +102,21 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
this.unmarshaller = unmarshaller;
}
/**
* Returns the fault resolver for this template.
*/
public FaultResolver getFaultResolver() {
return faultResolver;
}
/**
* Sets the fault resolver for this template.
*/
public void setFaultResolver(FaultResolver faultResolver) {
Assert.notNull(faultResolver, "faultResolver must not be null");
this.faultResolver = faultResolver;
}
public Object marshalSendAndReceive(final Object requestPayload) throws IOException {
return marshalSendAndReceive(requestPayload, null);
}
@@ -173,12 +193,15 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
requestCallback.doInMessage(messageContext.getRequest());
}
getMessageSender().sendAndReceive(messageContext);
if (messageContext.hasResponse()) {
return messageContext.getResponse();
}
else {
if (!messageContext.hasResponse()) {
return null;
}
WebServiceMessage response = messageContext.getResponse();
if (response.hasFault()) {
getFaultResolver().resolveFault(response);
return null;
}
return response;
}
private void checkMarshallerAndUnmarshaller() throws IllegalStateException {

View File

@@ -73,6 +73,10 @@ public class DomPoxMessage implements PoxMessage {
return false;
}
public String getFaultReason() {
return null;
}
public void writeTo(OutputStream outputStream) throws IOException {
try {
if (outputStream instanceof TransportOutputStream) {

View File

@@ -63,6 +63,18 @@ public abstract class AbstractSoapMessage implements SoapMessage {
return getSoapBody().hasFault();
}
/**
* Returns <code>getSoapBody().getFault().getFaultStringOrReason()</code>.
*/
public String getFaultReason() {
if (hasFault()) {
return getSoapBody().getFault().getFaultStringOrReason();
}
else {
return null;
}
}
public SoapVersion getVersion() {
if (version == null) {
String envelopeNamespace = getEnvelope().getName().getNamespaceURI();

View File

@@ -33,6 +33,12 @@ public interface SoapFault extends SoapElement {
*/
QName getFaultCode();
/**
* Returns the fault string or reason. For SOAP 1.1, this returns the fault string. For SOAP 1.2, this returns the
* fault reason for the default locale.
*/
String getFaultStringOrReason();
/**
* Returns the fault actor or role. For SOAP 1.1, this returns the actor. For SOAP 1.2, this returns the role.
*/

View File

@@ -35,7 +35,7 @@ class AxiomSoap11Fault extends AxiomSoapFault implements Soap11Fault {
super(axiomFault, axiomFactory);
}
public String getFaultString() {
public String getFaultStringOrReason() {
if (axiomFault.getReason() != null) {
SOAPFaultText soapText = axiomFault.getReason().getFirstSOAPText();
if (soapText != null) {

View File

@@ -117,6 +117,10 @@ class AxiomSoap12Fault extends AxiomSoapFault implements Soap12Fault {
}
}
public String getFaultStringOrReason() {
return getFaultReasonText(Locale.getDefault());
}
public String getFaultReasonText(Locale locale) {
SOAPFaultReason faultReason = axiomFault.getReason();
String language = AxiomUtils.toLanguage(locale);

View File

@@ -46,7 +46,7 @@ class SaajSoap11Fault extends SaajSoapFault implements Soap11Fault {
}
}
public String getFaultString() {
public String getFaultStringOrReason() {
return getImplementation().getFaultString(getSaajFault());
}

View File

@@ -90,6 +90,9 @@ class SaajSoap12Fault extends SaajSoapFault implements Soap12Fault {
catch (SOAPException ex) {
throw new SaajSoapFaultException(ex);
}
}
public String getFaultStringOrReason() {
return getFaultReasonText(Locale.getDefault());
}
}

View File

@@ -28,11 +28,6 @@ import org.springframework.ws.soap.SoapFault;
*/
public interface Soap11Fault extends SoapFault {
/**
* Returns the fault string.
*/
String getFaultString();
/**
* Returns the locale of the fault string.
*/

View File

@@ -48,6 +48,8 @@ public class MockWebServiceMessage implements WebServiceMessage {
private boolean fault = false;
private String faultReason;
public MockWebServiceMessage() {
content = new StringBuffer();
}
@@ -110,6 +112,14 @@ public class MockWebServiceMessage implements WebServiceMessage {
this.fault = fault;
}
public String getFaultReason() {
return faultReason;
}
public void setFaultReason(String faultReason) {
this.faultReason = faultReason;
}
public void writeTo(OutputStream outputStream) throws IOException {
PrintWriter writer = new PrintWriter(outputStream);
writer.write(content.toString());

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2007 the original author or authors.
*
* Licensed 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.springframework.ws.client.core;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.ws.WebServiceMessage;
public class SimpleFaultResolverTest extends TestCase {
private SimpleFaultResolver resolver;
protected void setUp() throws Exception {
resolver = new SimpleFaultResolver();
}
public void testResolveFault() throws Exception {
MockControl messageControl = MockControl.createControl(WebServiceMessage.class);
WebServiceMessage messageMock = (WebServiceMessage) messageControl.getMock();
String message = "message";
messageControl.expectAndReturn(messageMock.getFaultReason(), message);
messageControl.replay();
try {
resolver.resolveFault(messageMock);
fail("WebServiceFaultExcpetion expected");
}
catch (WebServiceFaultException ex) {
// expected
assertEquals("Invalid exception message", message, ex.getMessage());
}
messageControl.verify();
}
}

View File

@@ -84,6 +84,7 @@ public class WebServiceTemplateTest extends XMLTestCase {
public void testSendAndReceiveMessageResponse() throws Exception {
factoryControl.expectAndReturn(factoryMock.createWebServiceMessage(), requestMock);
factoryControl.expectAndReturn(factoryMock.createWebServiceMessage(), responseMock);
messageControl.expectAndReturn(responseMock.hasFault(), false);
template.setMessageSender(new ResponseMessageSender());
replayMockControls();
WebServiceMessage response = template.sendAndReceive(new WebServiceMessageCallback() {
@@ -108,9 +109,31 @@ public class WebServiceTemplateTest extends XMLTestCase {
verifyMockControls();
}
public void testSendAndReceiveMessageFaultResponse() throws Exception {
MockControl resolverControl = MockControl.createControl(FaultResolver.class);
FaultResolver resolverMock = (FaultResolver) resolverControl.getMock();
template.setFaultResolver(resolverMock);
factoryControl.expectAndReturn(factoryMock.createWebServiceMessage(), requestMock);
factoryControl.expectAndReturn(factoryMock.createWebServiceMessage(), responseMock);
messageControl.expectAndReturn(responseMock.hasFault(), true);
resolverMock.resolveFault(responseMock);
template.setMessageSender(new ResponseMessageSender());
replayMockControls();
resolverControl.replay();
WebServiceMessage response = template.sendAndReceive(new WebServiceMessageCallback() {
public void doInMessage(WebServiceMessage message) throws IOException {
assertEquals("Invalid request message", requestMock, message);
}
});
assertNull("Invalid response", response);
verifyMockControls();
resolverControl.verify();
}
public void testSendAndReceiveSourceResponse() throws Exception {
factoryControl.expectAndReturn(factoryMock.createWebServiceMessage(), requestMock);
factoryControl.expectAndReturn(factoryMock.createWebServiceMessage(), responseMock);
messageControl.expectAndReturn(responseMock.hasFault(), false);
messageControl.expectAndReturn(requestMock.getPayloadResult(), new StringResult());
Source expected = new StringSource("<response/>");
messageControl.expectAndReturn(responseMock.getPayloadSource(), expected);
@@ -132,6 +155,7 @@ public class WebServiceTemplateTest extends XMLTestCase {
public void testSendAndReceiveResultResponse() throws Exception {
factoryControl.expectAndReturn(factoryMock.createWebServiceMessage(), requestMock);
factoryControl.expectAndReturn(factoryMock.createWebServiceMessage(), responseMock);
messageControl.expectAndReturn(responseMock.hasFault(), false);
messageControl.expectAndReturn(requestMock.getPayloadResult(), new StringResult());
Source expected = new StringSource("<response/>");
messageControl.expectAndReturn(responseMock.getPayloadSource(), expected);
@@ -159,6 +183,7 @@ public class WebServiceTemplateTest extends XMLTestCase {
messageControl.expectAndReturn(requestMock.getPayloadResult(), requestResult);
marshallerMock.marshal(request, requestResult);
factoryControl.expectAndReturn(factoryMock.createWebServiceMessage(), responseMock);
messageControl.expectAndReturn(responseMock.hasFault(), false);
messageControl.expectAndReturn(responseMock.getPayloadSource(), responseSource);
unmarshallerControl.expectAndReturn(unmarshallerMock.unmarshal(responseSource), expected);

View File

@@ -86,7 +86,7 @@ public class PayloadValidatingInterceptorTest extends XMLTestCase {
assertEquals("Invalid fault code on fault", SoapVersion.SOAP_11.getClientOrSenderFaultName(),
fault.getFaultCode());
assertEquals("Invalid fault string on fault", PayloadValidatingInterceptor.DEFAULT_FAULTSTRING_OR_REASON,
fault.getFaultString());
fault.getFaultStringOrReason());
assertNotNull("No Detail on fault", fault.getFaultDetail());
}
@@ -129,7 +129,7 @@ public class PayloadValidatingInterceptorTest extends XMLTestCase {
Soap11Fault fault = (Soap11Fault) response.getSoapBody().getFault();
assertEquals("Invalid fault code on fault", SoapVersion.SOAP_11.getClientOrSenderFaultName(),
fault.getFaultCode());
assertEquals("Invalid fault string on fault", faultString, fault.getFaultString());
assertEquals("Invalid fault string on fault", faultString, fault.getFaultStringOrReason());
assertEquals("Invalid fault string locale on fault", locale, fault.getFaultStringLocale());
assertNull("Detail on fault", fault.getFaultDetail());
}

View File

@@ -44,7 +44,7 @@ public class AxiomSoap11BodyTest extends AbstractSoap11BodyTestCase {
assertTrue("SoapBody has no fault", soapBody.hasFault());
assertNotNull("SoapBody has no fault", soapBody.getFault());
assertEquals("Invalid fault code", faultCode, fault.getFaultCode());
assertEquals("Invalid fault string", faultString, fault.getFaultString());
assertEquals("Invalid fault string", faultString, fault.getFaultStringOrReason());
String actor = "http://www.springframework.org/actor";
fault.setFaultActorOrRole(actor);
assertEquals("Invalid fault actor", actor, fault.getFaultActorOrRole());

View File

@@ -128,7 +128,7 @@ public class SoapMessageDispatcherTest extends TestCase {
assertEquals("Invalid fault code", new QName(SOAPConstants.URI_NS_SOAP_1_1_ENVELOPE, "MustUnderstand"),
fault.getFaultCode());
assertEquals("Invalid fault string", SoapMessageDispatcher.DEFAULT_MUST_UNDERSTAND_FAULT,
fault.getFaultString());
fault.getFaultStringOrReason());
assertEquals("Invalid fault string locale", Locale.ENGLISH, fault.getFaultStringLocale());
assertEquals("Invalid fault actor", SOAPConstants.URI_SOAP_ACTOR_NEXT, fault.getFaultActorOrRole());
interceptorControl.verify();

View File

@@ -73,7 +73,7 @@ public class SoapFaultMappingExceptionResolverTest extends XMLTestCase {
Soap11Fault fault = (Soap11Fault) response.getSoapBody().getFault();
assertEquals("Invalid fault code on fault", SoapVersion.SOAP_11.getClientOrSenderFaultName(),
fault.getFaultCode());
assertEquals("Invalid fault string on fault", "Client error", fault.getFaultString());
assertEquals("Invalid fault string on fault", "Client error", fault.getFaultStringOrReason());
assertNull("Detail on fault", fault.getFaultDetail());
}
@@ -121,7 +121,7 @@ public class SoapFaultMappingExceptionResolverTest extends XMLTestCase {
Soap11Fault fault = (Soap11Fault) response.getSoapBody().getFault();
assertEquals("Invalid fault code on fault", SoapVersion.SOAP_11.getServerOrReceiverFaultName(),
fault.getFaultCode());
assertEquals("Invalid fault string on fault", "Server error", fault.getFaultString());
assertEquals("Invalid fault string on fault", "Server error", fault.getFaultStringOrReason());
assertNull("Detail on fault", fault.getFaultDetail());
}
@@ -171,7 +171,7 @@ public class SoapFaultMappingExceptionResolverTest extends XMLTestCase {
Soap11Fault fault = (Soap11Fault) response.getSoapBody().getFault();
assertEquals("Invalid fault code on fault", SoapVersion.SOAP_11.getClientOrSenderFaultName(),
fault.getFaultCode());
assertEquals("Invalid fault string on fault", "faultstring", fault.getFaultString());
assertEquals("Invalid fault string on fault", "faultstring", fault.getFaultStringOrReason());
assertNull("Detail on fault", fault.getFaultDetail());
}

View File

@@ -75,7 +75,7 @@ public abstract class AbstractSoap11BodyTestCase extends AbstractSoapBodyTestCas
assertTrue("SoapBody has no fault", soapBody.hasFault());
assertNotNull("SoapBody has no fault", soapBody.getFault());
assertEquals("Invalid fault code", faultCode, fault.getFaultCode());
assertEquals("Invalid fault string", faultString, fault.getFaultString());
assertEquals("Invalid fault string", faultString, fault.getFaultStringOrReason());
assertEquals("Invalid fault string locale", Locale.ENGLISH, fault.getFaultStringLocale());
String actor = "http://www.springframework.org/actor";
fault.setFaultActorOrRole(actor);