Fixed SWS-137: Added checkConnectionForFault to WebServiceTemplate to with Web services which are not WS-I compliant

This commit is contained in:
Arjen Poutsma
2007-06-08 23:57:54 +00:00
parent b53493c052
commit 06cc6378f9
24 changed files with 317 additions and 132 deletions

View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>spring-ws</artifactId>
<groupId>org.springframework.ws</groupId>
@@ -135,10 +137,6 @@
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>

View File

@@ -0,0 +1,46 @@
/*
* 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;
import org.springframework.ws.soap.SoapFault;
import org.springframework.ws.soap.SoapMessage;
/**
* Sub-interface of {@link WebServiceMessage} that can contain special Fault messages. Fault messages (such as {@link
* SoapFault} SOAP Faults) often require different processing rules.
*
* @author Arjen Poutsma
* @see SoapMessage
*/
public interface FaultAwareWebServiceMessage extends WebServiceMessage {
/**
* Does this message have a fault?
*
* @return <code>true</code> if the message has a fault.
* @see #getFaultReason()
*/
boolean hasFault();
/**
* Returns the fault reason message.
*
* @return the fault reason message, if any; returns <code>null</code> when no fault is present.
* @see #hasFault()
*/
String getFaultReason();
}

View File

@@ -23,7 +23,7 @@ import javax.xml.transform.Source;
/**
* Represents a protocol-agnostic XML message.
*
* <p/>
* <p>Contains methods that provide access to the payload of the message.
*
* @author Arjen Poutsma
@@ -33,17 +33,16 @@ import javax.xml.transform.Source;
public interface WebServiceMessage {
/**
* Returns the contents of the message as a {@link Source}.
* <p> Depending on the implementation, this can be retrieved multiple times,
* or just a single time.
* Returns the contents of the message as a {@link Source}. <p> Depending on the implementation, this can be
* retrieved multiple times, or just a single time.
*
* @return the message contents
*/
Source getPayloadSource();
/**
* Returns the contents of the message as a {@link Result}.
* <p>Implementations that are read-only will throw an {@link UnsupportedOperationException}.
* Returns the contents of the message as a {@link Result}. <p>Implementations that are read-only will throw an
* {@link UnsupportedOperationException}.
*
* @return the message contents
* @throws UnsupportedOperationException if the message is read-only
@@ -51,30 +50,12 @@ public interface WebServiceMessage {
Result getPayloadResult();
/**
* Writes the entire message to the given output stream.
* <p>If the given stream is an instance of
* {@link org.springframework.ws.transport.TransportOutputStream}, the
* corresponding headers will be written as well.
* Writes the entire message to the given output stream. <p>If the given stream is an instance of {@link
* org.springframework.ws.transport.TransportOutputStream}, the corresponding headers will be written as well.
*
* @param outputStream the stream to write to
* @throws IOException if an I/O exception occurs
*/
void writeTo(OutputStream outputStream) throws IOException;
/**
* Does this message have a fault?
*
* @return <code>true</code> if the message has a fault.
* @see #getFaultReason()
*/
boolean hasFault();
/**
* Returns the fault reason message.
*
* @return the fault reason message, if any; returns <code>null</code> when no fault is present.
* @see #hasFault()
*/
String getFaultReason();
}

View File

@@ -16,7 +16,7 @@
package org.springframework.ws.client;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.FaultAwareWebServiceMessage;
/**
* Thrown by <code>SimpleFaultMessageResolver</code> when the response message has a fault.
@@ -25,20 +25,26 @@ import org.springframework.ws.WebServiceMessage;
*/
public class WebServiceFaultException extends WebServiceClientException {
private final WebServiceMessage webServiceMessage;
private final FaultAwareWebServiceMessage faultMessage;
/** Create a new instance of the <code>WebServiceFaultException</code> class. */
public WebServiceFaultException(String msg) {
super(msg);
faultMessage = null;
}
/**
* Create a new instance of the <code>WebServiceFaultException</code> class.
*
* @param faultMessage the fault message
*/
public WebServiceFaultException(WebServiceMessage faultMessage) {
public WebServiceFaultException(FaultAwareWebServiceMessage faultMessage) {
super(faultMessage.getFaultReason());
webServiceMessage = faultMessage;
this.faultMessage = faultMessage;
}
/** Returns the fault message. */
public WebServiceMessage getWebServiceMessage() {
return webServiceMessage;
public FaultAwareWebServiceMessage getWebServiceMessage() {
return faultMessage;
}
}

View File

@@ -16,6 +16,7 @@
package org.springframework.ws.client.core;
import org.springframework.ws.FaultAwareWebServiceMessage;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.WebServiceFaultException;
@@ -29,6 +30,11 @@ public class SimpleFaultMessageResolver implements FaultMessageResolver {
/** Throws a new <code>WebServiceFaultException</code>. */
public void resolveFault(WebServiceMessage message) {
throw new WebServiceFaultException(message);
if (message instanceof FaultAwareWebServiceMessage) {
throw new WebServiceFaultException((FaultAwareWebServiceMessage) message);
}
else {
throw new WebServiceFaultException("Message has unknown fault: " + message);
}
}
}

View File

@@ -33,6 +33,7 @@ import org.springframework.oxm.Unmarshaller;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.ws.FaultAwareWebServiceMessage;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.client.WebServiceIOException;
@@ -73,6 +74,8 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
private String defaultUri;
private boolean checkConnectionForFault = true;
/** Creates a new <code>WebServiceTemplate</code> using default settings. */
public WebServiceTemplate() {
initDefaultStrategies();
@@ -142,6 +145,25 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
this.faultMessageResolver = faultMessageResolver;
}
/**
* Indicates whether the {@link FaultAwareWebServiceConnection#hasFault() connection} should be checked for fault
* indicators (<code>true</code>), or whether we should rely on the {@link FaultAwareWebServiceMessage#hasFault()
* message} only (<code>false</code>). The default is <code>true</code>.
* <p/>
* When using a HTTP transport, this property defines whether to check the HTTP response status code for fault
* indicators. Both the SOAP specification and the WS-I Basic Profile define that a Web service must return a "500
* Internal Server Error" HTTP status code if the response envelope is a Fault. Setting this property to
* <code>false</code> allows this template to deal with non-conformant services.
*
* @see #hasFault(WebServiceConnection,WebServiceMessage)
* @see <a href="http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383529">SOAP 1.1 specification</a>
* @see <a href="http://www.ws-i.org/Profiles/BasicProfile-1.1.html#HTTP_Server_Error_Status_Codes">WS-I Basic
* Profile</a>
*/
public void setCheckConnectionForFault(boolean checkConnectionForFault) {
this.checkConnectionForFault = checkConnectionForFault;
}
/**
* Initialize the default implementations for the template's strategies: {@link SoapFaultMessageResolver}, {@link
* org.springframework.ws.soap.saaj.SaajSoapMessageFactory}, and {@link HttpUrlConnectionMessageSender}.
@@ -358,7 +380,7 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
requestCallback.doWithMessage(request);
}
sendRequest(connection, request);
if (connection.hasError()) {
if (hasError(connection, request)) {
return handleError(connection, request);
}
WebServiceMessage response = connection.receive(getMessageFactory());
@@ -396,23 +418,28 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
}
/**
* Determines whether the given connection or message context has a fault. Default implementation checks whether the
* connection is a {@link FaultAwareWebServiceConnection}, and calls returns {@link
* FaultAwareWebServiceConnection#hasFault()} if so. Otherwise, {@link WebServiceMessage#hasFault()} is returned
* (which required a full message parse).
* Determines whether the given connection or message context has an error.
* <p/>
* This implementation checks the {@link WebServiceConnection#hasError() connection} first. If it indicates an
* error, it makes sure that it is not a {@link FaultAwareWebServiceConnection#hasFault() fault}.
*
* @param connection the connection (possibly a {@link FaultAwareWebServiceConnection}
* @param response the response message
* @return <code>true</code> if either the connection or the message has a fault; <code>false</code> otherwise
* @param request the response message (possibly a {@link FaultAwareWebServiceMessage}
* @return <code>true</code> if the connection has an error; <code>false</code> otherwise
* @throws IOException in case of I/O errors
*/
protected boolean hasFault(WebServiceConnection connection, WebServiceMessage response) throws IOException {
if (connection instanceof FaultAwareWebServiceConnection) {
return ((FaultAwareWebServiceConnection) connection).hasFault();
}
else {
return response.hasFault();
protected boolean hasError(WebServiceConnection connection, WebServiceMessage request) throws IOException {
if (connection.hasError()) {
// this could be a fault rather than an error
if (connection instanceof FaultAwareWebServiceConnection) {
FaultAwareWebServiceConnection faultConnection = (FaultAwareWebServiceConnection) connection;
if (faultConnection.hasFault() && request instanceof FaultAwareWebServiceMessage) {
return false;
}
}
return true;
}
return false;
}
/**
@@ -425,10 +452,38 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
*WebServiceMessageExtractor)}, if any
*/
protected Object handleError(WebServiceConnection connection, WebServiceMessage request) throws IOException {
logger.debug("Received " + connection.getErrorMessage() + " error for request [" + request + "]");
logger.warn("Received " + connection.getErrorMessage() + " error for request [" + request + "]");
throw new WebServiceTransportException(connection.getErrorMessage());
}
/**
* Determines whether the given connection or message has a fault.
* <p/>
* This implementation checks the {@link FaultAwareWebServiceConnection#hasFault() connection} if the {@link
* #setCheckConnectionForFault(boolean) checkConnectionForFault} property is true, and defaults to the {@link
* FaultAwareWebServiceMessage#hasFault() message} otherwise.
*
* @param connection the connection (possibly a {@link FaultAwareWebServiceConnection}
* @param response the response message (possibly a {@link FaultAwareWebServiceMessage}
* @return <code>true</code> if either the connection or the message has a fault; <code>false</code> otherwise
* @throws IOException in case of I/O errors
*/
protected boolean hasFault(WebServiceConnection connection, WebServiceMessage response) throws IOException {
if (checkConnectionForFault && connection instanceof FaultAwareWebServiceConnection) {
// check whether the connection has a fault (i.e. status code 500 in HTTP)
FaultAwareWebServiceConnection faultConnection = (FaultAwareWebServiceConnection) connection;
if (!faultConnection.hasFault()) {
return false;
}
}
if (response instanceof FaultAwareWebServiceMessage) {
// either the connection has a fault, or checkConnectionForFault is false: let's verify the fault
FaultAwareWebServiceMessage faultMessage = (FaultAwareWebServiceMessage) response;
return faultMessage.hasFault();
}
return false;
}
/**
* Handles an fault in the given response message. The default implementation invokes the {@link
* FaultMessageResolver fault resolver} if registered, or invokes {@link #handleError(WebServiceConnection,

View File

@@ -36,7 +36,9 @@ import org.springframework.core.io.Resource;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.ws.FaultAwareWebServiceMessage;
import org.springframework.ws.NoEndpointFoundException;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MessageEndpoint;
import org.springframework.ws.server.endpoint.PayloadEndpoint;
@@ -322,8 +324,12 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa
MessageContext messageContext) throws Exception {
if (mappedEndpoint != null && messageContext.hasResponse() &&
!ObjectUtils.isEmpty(mappedEndpoint.getInterceptors())) {
boolean hasFault = false;
WebServiceMessage response = messageContext.getResponse();
if (response instanceof FaultAwareWebServiceMessage) {
hasFault = ((FaultAwareWebServiceMessage) response).hasFault();
}
boolean resume = true;
boolean hasFault = messageContext.getResponse().hasFault();
for (int i = interceptorIndex; resume && i >= 0; i--) {
EndpointInterceptor interceptor = mappedEndpoint.getInterceptors()[i];
if (!hasFault) {

View File

@@ -16,6 +16,7 @@
package org.springframework.ws.soap;
import org.springframework.ws.FaultAwareWebServiceMessage;
import org.springframework.ws.mime.MimeMessage;
/**
@@ -28,7 +29,7 @@ import org.springframework.ws.mime.MimeMessage;
* @see #getPayloadResult()
* @see #getEnvelope()
*/
public interface SoapMessage extends MimeMessage {
public interface SoapMessage extends MimeMessage, FaultAwareWebServiceMessage {
/** Returns the <code>SoapEnvelope</code> associated with this <code>SoapMessage</code>. */
SoapEnvelope getEnvelope() throws SoapEnvelopeException;

View File

@@ -18,20 +18,34 @@ package org.springframework.ws.transport;
import java.io.IOException;
import org.springframework.ws.soap.SoapFault;
/**
* Sub-interface of {@link WebServiceConnection} that is aware of any Fault messages received. Fault messages (such as
* SOAP Faults often require different processing rules. Typically, fault detection is done by inspecting connection
* error codes, etc.
* {@link SoapFault} SOAP Faults) often require different processing rules. Typically, fault detection is done by
* inspecting connection error codes, etc.
*
* @author Arjen Poutsma
*/
public interface FaultAwareWebServiceConnection extends WebServiceConnection {
/**
* Indicates whether this connection has a Fault.
* Indicates whether this connection received a fault.
* <p/>
* Typically implemented by looking at an HTTP status code.
*
* @return <code>true</code> if this connection has a fault; <code>false</code> otherwise.
* @return <code>true</code> if this connection received a fault; <code>false</code> otherwise.
* @throws IOException in case of I/O errors
*/
boolean hasFault() throws IOException;
/**
* Sets whether this connection will send a fault.
* <p/>
* Typically implemented by setting an HTTP status code.
*
* @param fault <code>true</code> if this will send a fault; <code>false</code> otherwise.
* @throws IOException in case of I/O errors
*/
void setFault(boolean fault) throws IOException;
}

View File

@@ -35,16 +35,20 @@ import org.springframework.ws.transport.WebServiceConnection;
public abstract class AbstractHttpSenderConnection extends AbstractSenderConnection
implements FaultAwareWebServiceConnection {
protected static final String HTTP_HEADER_CONTENT_ENCODING = "Content-Encoding";
protected static final String ENCODING_GZIP = "gzip";
protected static final int HTTP_STATUS_INTERNAL_SERVER_ERROR = 500;
/** Buffer used for reading the response, when the content length is invalid. */
private byte[] responseBuffer;
public final boolean hasError() throws IOException {
return getResponseCode() / 100 != 2;
}
/*
* Receiving response
*/
protected final boolean hasResponse() throws IOException {
if (getResponseCode() == HttpTransportConstants.STATUS_ACCEPTED) {
return false;
}
long contentLength = getResponseContentLength();
if (contentLength < 0) {
if (responseBuffer == null) {
@@ -55,15 +59,6 @@ public abstract class AbstractHttpSenderConnection extends AbstractSenderConnect
return contentLength > 0;
}
public final boolean hasError() throws IOException {
int code = getResponseCode();
return code / 100 != 2 && code != HTTP_STATUS_INTERNAL_SERVER_ERROR;
}
public final boolean hasFault() throws IOException {
return getResponseCode() == HTTP_STATUS_INTERNAL_SERVER_ERROR;
}
protected final InputStream getResponseInputStream() throws IOException {
InputStream inputStream;
if (responseBuffer != null) {
@@ -77,9 +72,10 @@ public abstract class AbstractHttpSenderConnection extends AbstractSenderConnect
/** Determine whether the given response is a GZIP response. */
private boolean isGzipResponse() throws IOException {
for (Iterator iterator = getResponseHeaders(HTTP_HEADER_CONTENT_ENCODING); iterator.hasNext();) {
for (Iterator iterator = getResponseHeaders(HttpTransportConstants.HEADER_CONTENT_ENCODING);
iterator.hasNext();) {
String encodingHeader = (String) iterator.next();
return encodingHeader.toLowerCase().indexOf(ENCODING_GZIP) != -1;
return encodingHeader.toLowerCase().indexOf(HttpTransportConstants.CONTENT_ENCODING_GZIP) != -1;
}
return false;
}
@@ -92,5 +88,15 @@ public abstract class AbstractHttpSenderConnection extends AbstractSenderConnect
protected abstract InputStream getRawResponseInputStream() throws IOException;
/*
* Faults
*/
public final boolean hasFault() throws IOException {
return getResponseCode() == HttpTransportConstants.STATUS_INTERNAL_SERVER_ERROR;
}
public final void setFault(boolean fault) {
}
}

View File

@@ -43,9 +43,9 @@ public class CommonsHttpConnection extends AbstractHttpSenderConnection {
private final PostMethod postMethod;
private ByteArrayOutputStream bufferedOutput;
private ByteArrayOutputStream requestBuffer;
public CommonsHttpConnection(HttpClient httpClient, PostMethod postMethod) {
protected CommonsHttpConnection(HttpClient httpClient, PostMethod postMethod) {
Assert.notNull(httpClient, "httpClient must not be null");
Assert.notNull(postMethod, "postMethod must not be null");
this.httpClient = httpClient;
@@ -69,7 +69,7 @@ public class CommonsHttpConnection extends AbstractHttpSenderConnection {
*/
protected void onSendBeforeWrite(WebServiceMessage message) throws IOException {
bufferedOutput = new ByteArrayOutputStream();
requestBuffer = new ByteArrayOutputStream();
}
protected void addRequestHeader(String name, String value) throws IOException {
@@ -77,12 +77,12 @@ public class CommonsHttpConnection extends AbstractHttpSenderConnection {
}
protected OutputStream getRequestOutputStream() throws IOException {
return bufferedOutput;
return requestBuffer;
}
protected void onSendAfterWrite(WebServiceMessage message) throws IOException {
postMethod.setRequestEntity(new ByteArrayRequestEntity(bufferedOutput.toByteArray()));
bufferedOutput = null;
postMethod.setRequestEntity(new ByteArrayRequestEntity(requestBuffer.toByteArray()));
requestBuffer = null;
httpClient.executeMethod(postMethod);
}

View File

@@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.transport.AbstractReceiverConnection;
import org.springframework.ws.transport.EndpointAwareWebServiceConnection;
import org.springframework.ws.transport.FaultAwareWebServiceConnection;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.support.EnumerationIterator;
@@ -34,21 +35,20 @@ import org.springframework.ws.transport.support.EnumerationIterator;
*
* @author Arjen Poutsma
*/
public class HttpServletConnection extends AbstractReceiverConnection implements EndpointAwareWebServiceConnection {
public class HttpServletConnection extends AbstractReceiverConnection
implements EndpointAwareWebServiceConnection, FaultAwareWebServiceConnection {
private final HttpServletRequest httpServletRequest;
private final HttpServletResponse httpServletResponse;
private boolean sentResponse = false;
private boolean endpointFound = true;
private boolean statusCodeSet = false;
/**
* Constructs a new servlet connection with the given <code>HttpServletRequest</code> and
* <code>HttpServletResponse</code>.
*/
public HttpServletConnection(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
protected HttpServletConnection(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
this.httpServletRequest = httpServletRequest;
this.httpServletResponse = httpServletResponse;
}
@@ -64,8 +64,8 @@ public class HttpServletConnection extends AbstractReceiverConnection implements
}
public void endpointNotFound() {
endpointFound = false;
getHttpServletResponse().setStatus(HttpServletResponse.SC_NOT_FOUND);
getHttpServletResponse().setStatus(HttpTransportConstants.STATUS_NOT_FOUND);
statusCodeSet = true;
}
public boolean hasError() throws IOException {
@@ -76,12 +76,6 @@ public class HttpServletConnection extends AbstractReceiverConnection implements
return null;
}
public void close() throws IOException {
if (!sentResponse && endpointFound) {
getHttpServletResponse().setStatus(HttpServletResponse.SC_ACCEPTED);
}
}
/*
* Receiving request
*/
@@ -110,13 +104,31 @@ public class HttpServletConnection extends AbstractReceiverConnection implements
return getHttpServletResponse().getOutputStream();
}
protected void onSendBeforeWrite(WebServiceMessage message) throws IOException {
sentResponse = true;
if (!message.hasFault()) {
getHttpServletResponse().setStatus(HttpServletResponse.SC_OK);
}
else {
getHttpServletResponse().setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
protected void onSendAfterWrite(WebServiceMessage message) throws IOException {
statusCodeSet = true;
}
public void close() throws IOException {
if (!statusCodeSet) {
getHttpServletResponse().setStatus(HttpTransportConstants.STATUS_ACCEPTED);
}
}
/*
* Faults
*/
public boolean hasFault() throws IOException {
return false;
}
public void setFault(boolean fault) throws IOException {
if (fault) {
getHttpServletResponse().setStatus(HttpTransportConstants.STATUS_INTERNAL_SERVER_ERROR);
}
else {
getHttpServletResponse().setStatus(HttpTransportConstants.STATUS_OK);
}
statusCodeSet = true;
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.transport.http;
import org.springframework.ws.transport.TransportConstants;
/**
* Declares HTTP-specific transport constants.
*
* @author Arjen Poutsma
*/
public interface HttpTransportConstants extends TransportConstants {
/** The "Content-Encoding" header. */
String HEADER_CONTENT_ENCODING = "Content-Encoding";
/** Header value that indicates a compressed "Content-Encoding". */
String CONTENT_ENCODING_GZIP = "gzip";
/** The "200 OK" status code. */
int STATUS_OK = 200;
/** The "202 Accepted" status code. */
int STATUS_ACCEPTED = 202;
/** The "404 Not Found" status code. */
int STATUS_NOT_FOUND = 404;
/** The "500 Server Error" status code. */
int STATUS_INTERNAL_SERVER_ERROR = 500;
}

View File

@@ -45,7 +45,7 @@ public class HttpUrlConnection extends AbstractHttpSenderConnection {
*
* @param connection the <code>HttpURLConnection</code>
*/
public HttpUrlConnection(HttpURLConnection connection) {
protected HttpUrlConnection(HttpURLConnection connection) {
Assert.notNull(connection, "connection must not be null");
this.connection = connection;
}

View File

@@ -64,7 +64,7 @@ import org.springframework.ws.wsdl.WsdlDefinition;
public class MessageDispatcherServlet extends FrameworkServlet {
/** Well-known name for the {@link WebServiceMessageFactory} bean in the bean factory for this namespace. */
public static final String WEB_SERVICE_MESSAGE_FACTORY_BEAN_NAME = "messageFactory";
public static final String MESSAGE_FACTORY_BEAN_NAME = "messageFactory";
/** Well-known name for the {@link WebServiceMessageReceiver} object in the bean factory for this namespace. */
public static final String MESSAGE_RECEIVER_BEAN_NAME = "messageReceiver";
@@ -181,7 +181,7 @@ public class MessageDispatcherServlet extends FrameworkServlet {
WebServiceMessageFactory messageFactory;
try {
messageFactory = (WebServiceMessageFactory) getWebApplicationContext()
.getBean(WEB_SERVICE_MESSAGE_FACTORY_BEAN_NAME, WebServiceMessageFactory.class);
.getBean(MESSAGE_FACTORY_BEAN_NAME, WebServiceMessageFactory.class);
}
catch (NoSuchBeanDefinitionException ignored) {
messageFactory = (WebServiceMessageFactory) defaultStrategiesHelper

View File

@@ -22,12 +22,14 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.ws.FaultAwareWebServiceMessage;
import org.springframework.ws.NoEndpointFoundException;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.transport.EndpointAwareWebServiceConnection;
import org.springframework.ws.transport.FaultAwareWebServiceConnection;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.WebServiceMessageReceiver;
import org.springframework.ws.transport.context.DefaultTransportContext;
@@ -63,8 +65,9 @@ public abstract class WebServiceMessageReceiverObjectSupport implements Initiali
}
/**
* Handles an incoming connection by reading a message from the connection input stream, passing it to the receiver,
* and writing the response (if any) to the output stream.
* Handles an incoming connection by {@link WebServiceConnection#receive(WebServiceMessageFactory) receving} a
* message from it, passing it to the {@link WebServiceMessageReceiver#receive(MessageContext) receiver}, and {@link
* WebServiceConnection#send(WebServiceMessage) sending} the response (if any).
* <p/>
* Stores the given connection in the transport context.
*
@@ -82,6 +85,13 @@ public abstract class WebServiceMessageReceiverObjectSupport implements Initiali
MessageContext messageContext = new DefaultMessageContext(request, getMessageFactory());
receiver.receive(messageContext);
if (messageContext.hasResponse()) {
WebServiceMessage response = messageContext.getResponse();
if (response instanceof FaultAwareWebServiceMessage &&
connection instanceof FaultAwareWebServiceConnection) {
FaultAwareWebServiceMessage faultResponse = (FaultAwareWebServiceMessage) response;
FaultAwareWebServiceConnection faultConnection = (FaultAwareWebServiceConnection) connection;
faultConnection.setFault(faultResponse.hasFault());
}
connection.send(messageContext.getResponse());
}
}

View File

@@ -75,10 +75,6 @@ public abstract class AbstractWebServiceMessageTestCase extends XMLTestCase {
XMLUnit.setIgnoreWhitespace(true);
}
public void testHasFault() throws Exception {
assertFalse("Message has fault", webServiceMessage.hasFault());
}
public void testDomPayload() throws Exception {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);

View File

@@ -42,7 +42,7 @@ import org.springframework.xml.transform.StringSource;
*
* @author Arjen Poutsma
*/
public class MockWebServiceMessage implements WebServiceMessage {
public class MockWebServiceMessage implements FaultAwareWebServiceMessage {
private final StringBuffer content;

View File

@@ -18,7 +18,7 @@ package org.springframework.ws.client.core;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.FaultAwareWebServiceMessage;
import org.springframework.ws.client.WebServiceFaultException;
public class SimpleFaultMessageResolverTest extends TestCase {
@@ -30,8 +30,8 @@ public class SimpleFaultMessageResolverTest extends TestCase {
}
public void testResolveFault() throws Exception {
MockControl messageControl = MockControl.createControl(WebServiceMessage.class);
WebServiceMessage messageMock = (WebServiceMessage) messageControl.getMock();
MockControl messageControl = MockControl.createControl(FaultAwareWebServiceMessage.class);
FaultAwareWebServiceMessage messageMock = (FaultAwareWebServiceMessage) messageControl.getMock();
String message = "message";
messageControl.expectAndReturn(messageMock.getFaultReason(), message);
messageControl.replay();

View File

@@ -50,7 +50,6 @@ import org.springframework.ws.pox.dom.DomPoxMessageFactory;
import org.springframework.ws.soap.SoapMessageFactory;
import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
import org.springframework.ws.soap.client.SoapFaultClientException;
import org.springframework.ws.soap.client.core.SoapFaultMessageResolver;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
import org.springframework.ws.transport.http.CommonsHttpMessageSender;
import org.springframework.xml.transform.StringResult;
@@ -74,9 +73,6 @@ public class WebServiceTemplateIntegrationTest extends XMLTestCase {
jettyContext.addServlet(new ServletHolder(new ErrorServlet(404)), "/errors/notfound");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(500)), "/errors/server");
jettyServer.start();
template = new WebServiceTemplate();
template.setMessageSender(new CommonsHttpMessageSender());
template.setFaultMessageResolver(new SoapFaultMessageResolver());
}
protected void tearDown() throws Exception {
@@ -88,8 +84,8 @@ public class WebServiceTemplateIntegrationTest extends XMLTestCase {
}
public void testPox() throws Exception {
template.setMessageFactory(new DomPoxMessageFactory());
template.setFaultMessageResolver(null);
template = new WebServiceTemplate(new DomPoxMessageFactory());
template.setMessageSender(new CommonsHttpMessageSender());
String content = "<root xmlns='http://springframework.org/spring-ws'><child/></root>";
StringResult result = new StringResult();
template.sendAndReceive("http://localhost:8888/pox", new StringSource(content), result);
@@ -117,7 +113,8 @@ public class WebServiceTemplateIntegrationTest extends XMLTestCase {
private void testSoap(SoapMessageFactory messageFactory)
throws SAXException, IOException, ParserConfigurationException {
template.setMessageFactory(messageFactory);
template = new WebServiceTemplate(messageFactory);
template.setMessageSender(new CommonsHttpMessageSender());
String content = "<root xmlns='http://springframework.org/spring-ws'><child/></root>";
StringResult result = new StringResult();
template.sendAndReceive("http://localhost:8888/soap/echo", new StringSource(content), result);

View File

@@ -117,7 +117,6 @@ public class WebServiceTemplateTest extends XMLTestCase {
callbackControl.verify();
extractorControl.verify();
connectionControl.verify();
}
public void testSendAndReceiveMessageNoResponse() throws Exception {
@@ -150,11 +149,15 @@ public class WebServiceTemplateTest extends XMLTestCase {
faultResolverControl.setMatcher(MockControl.ALWAYS_MATCHER);
faultResolverControl.replay();
MockWebServiceMessage response = new MockWebServiceMessage("<response/>");
response.setFault(true);
connectionMock.send(null);
connectionControl.setMatcher(MockControl.ALWAYS_MATCHER);
connectionControl.expectAndReturn(connectionMock.hasError(), false);
connectionControl.expectAndReturn(connectionMock.hasError(), true);
connectionControl.expectAndReturn(connectionMock.hasFault(), true);
connectionControl
.expectAndReturn(connectionMock.receive(messageFactory), new MockWebServiceMessage("<response/>"));
.expectAndReturn(connectionMock.receive(messageFactory), response);
connectionControl.expectAndReturn(connectionMock.hasFault(), true);
connectionMock.close();
connectionControl.replay();
@@ -177,6 +180,7 @@ public class WebServiceTemplateTest extends XMLTestCase {
connectionMock.send(null);
connectionControl.setMatcher(MockControl.ALWAYS_MATCHER);
connectionControl.expectAndReturn(connectionMock.hasError(), true);
connectionControl.expectAndReturn(connectionMock.hasFault(), false);
String errorMessage = "errorMessage";
connectionControl.expectAndReturn(connectionMock.getErrorMessage(), errorMessage, 2);
connectionMock.close();

View File

@@ -20,7 +20,6 @@ import java.io.ByteArrayOutputStream;
import java.util.Iterator;
import java.util.Locale;
import javax.activation.DataHandler;
import javax.mail.util.ByteArrayDataSource;
import javax.xml.namespace.QName;
import javax.xml.soap.AttachmentPart;
import javax.xml.soap.Detail;
@@ -273,7 +272,7 @@ public abstract class AbstractSaajImplementationTestCase extends XMLTestCase {
}
public void testAddAttachmentPart() throws Exception {
DataHandler dataHandler = new DataHandler(new ByteArrayDataSource("data", "text"));
DataHandler dataHandler = new DataHandler("data", "text/plain");
AttachmentPart attachmentPart = implementation.addAttachmentPart(message, dataHandler);
assertNotNull("No attachment part", attachmentPart);
}

View File

@@ -22,8 +22,8 @@ import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.ws.FaultAwareWebServiceMessage;
import org.springframework.ws.NoEndpointFoundException;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.transport.WebServiceMessageReceiver;
@@ -48,9 +48,9 @@ public class WebServiceMessageReceiverHandlerAdapterTest extends TestCase {
private MockControl messageControl;
private WebServiceMessage responseMock;
private FaultAwareWebServiceMessage responseMock;
private WebServiceMessage requestMock;
private FaultAwareWebServiceMessage requestMock;
protected void setUp() throws Exception {
adapter = new WebServiceMessageReceiverHandlerAdapter();
@@ -59,9 +59,9 @@ public class WebServiceMessageReceiverHandlerAdapterTest extends TestCase {
factoryControl = MockControl.createControl(WebServiceMessageFactory.class);
factoryMock = (WebServiceMessageFactory) factoryControl.getMock();
adapter.setMessageFactory(factoryMock);
messageControl = MockControl.createControl(WebServiceMessage.class);
requestMock = (WebServiceMessage) messageControl.getMock();
responseMock = (WebServiceMessage) messageControl.getMock();
messageControl = MockControl.createControl(FaultAwareWebServiceMessage.class);
requestMock = (FaultAwareWebServiceMessage) messageControl.getMock();
responseMock = (FaultAwareWebServiceMessage) messageControl.getMock();
}
public void testHandleNonPost() throws Exception {

View File

@@ -6,6 +6,9 @@
</properties>
<body>
<release version="1.0-rc2">
<action dev="poutsma" type="add" issue="SWS-137">Added checkConnectionForFault to WebServiceTemplate to
deal with Web services which are not WS-I compliant
</action>
<action dev="poutsma" type="update">WebServiceTemplate returns boolean values rather than void</action>
<action dev="poutsma" type="update" issue="SWS-126">Changed WebServiceMessageCallback's doInMessage() to
doWithMessage()