Fixed SWS-137: Added checkConnectionForFault to WebServiceTemplate to with Web services which are not WS-I compliant
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user