- Changed name of FaultResolver to MessageFaultResolver

- Changed WebServiceMessageCallback's doInMessage() to doWithMessage()
- Added more integration tests for WebServiceTemplate
- Reduced verbosity of logging
- WebServiceTemplate returns boolean instead of void
- Made WebServiceTemplate SOAP agnostic by removing Fault-specific logic
- Moved client-side SOAP classes to soap package
- Added hasErrors() method to connection.
This commit is contained in:
Arjen Poutsma
2007-06-07 00:35:37 +00:00
parent c8189b13b4
commit 2f75e420a5
38 changed files with 920 additions and 404 deletions

View File

@@ -16,18 +16,29 @@
package org.springframework.ws.client;
import org.springframework.ws.WebServiceMessage;
/**
* Thrown by <code>SimpleFaultResolver</code> when the response message has a fault.
* Thrown by <code>SimpleFaultMessageResolver</code> when the response message has a fault.
*
* @author Arjen Poutsma
*/
public class WebServiceFaultException extends WebServiceClientException {
public WebServiceFaultException(String msg) {
super(msg);
private final WebServiceMessage webServiceMessage;
/**
* Create a new instance of the <code>WebServiceFaultException</code> class.
*
* @param faultMessage the fault message
*/
public WebServiceFaultException(WebServiceMessage faultMessage) {
super(faultMessage.getFaultReason());
webServiceMessage = faultMessage;
}
public WebServiceFaultException(String msg, Throwable ex) {
super(msg, ex);
/** Returns the fault message. */
public WebServiceMessage getWebServiceMessage() {
return webServiceMessage;
}
}

View File

@@ -21,11 +21,11 @@ import java.io.IOException;
import org.springframework.ws.WebServiceMessage;
/**
* Defines the interface for objects than can resolve faults in received {@link org.springframework.ws.WebServiceMessage}.
* Defines the interface for objects than can resolve fault {@link WebServiceMessage}.
*
* @author Arjen Poutsma
*/
public interface FaultResolver {
public interface FaultMessageResolver {
/**
* Try to resolve the given fault message that got received.

View File

@@ -20,16 +20,15 @@ import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.WebServiceFaultException;
/**
* Simple fault resolver that simply throws a {@link org.springframework.ws.client.WebServiceFaultException} when a
* fault occurs.
* Simple fault resolver that simply throws a {@link WebServiceFaultException} when a fault occurs.
*
* @author Arjen Poutsma
* @see org.springframework.ws.client.WebServiceFaultException
* @see WebServiceFaultException
*/
public class SimpleFaultResolver implements FaultResolver {
public class SimpleFaultMessageResolver implements FaultMessageResolver {
/** Throws a new <code>WebServiceFaultException</code>. */
public void resolveFault(WebServiceMessage message) {
throw new WebServiceFaultException(message.getFaultReason());
throw new WebServiceFaultException(message);
}
}

View File

@@ -22,20 +22,20 @@ import org.springframework.ws.WebServiceMessage;
/**
* Generic callback interface for code that operates on a {@link WebServiceMessage}.
*
* <p>Implementations can execute any number of operations on the message, such as
* set the contents of the message, or set the <code>SOAPAction</code> header.
* <p/>
* Implementations can execute any number of operations on the message, such as set the contents of the message, or set
* the <code>SOAPAction</code> header.
*
* @author Arjen Poutsma
*/
public interface WebServiceMessageCallback {
/**
* Execute any number of operations on the supplied <code>message</code>.
* Execute any number of operations on the supplied <code>message</code>.
*
* @param message the message
* @throws IOException in case of I/O errors
*/
void doInMessage(WebServiceMessage message) throws IOException;
void doWithMessage(WebServiceMessage message) throws IOException;
}

View File

@@ -166,9 +166,10 @@ public interface WebServiceOperations {
*
* @param requestPayload the payload of the request message
* @param responseResult the result to write the response payload to
* @return <code>true</code> if a response was received; <code>false</code> otherwise
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
void sendAndReceive(Source requestPayload, Result responseResult) throws WebServiceClientException;
boolean sendAndReceive(Source requestPayload, Result responseResult) throws WebServiceClientException;
/**
* Sends a web service message that contains the given payload. Writes the response, if any, to the given
@@ -177,9 +178,10 @@ public interface WebServiceOperations {
* @param uri the URI to send the message to
* @param requestPayload the payload of the request message
* @param responseResult the result to write the response payload to
* @return <code>true</code> if a response was received; <code>false</code> otherwise
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
void sendAndReceive(String uri, Source requestPayload, Result responseResult) throws WebServiceClientException;
boolean sendAndReceive(String uri, Source requestPayload, Result responseResult) throws WebServiceClientException;
/**
* Sends a web service message that contains the given payload. Writes the response, if any, to the given
@@ -192,9 +194,10 @@ public interface WebServiceOperations {
* @param requestPayload the payload of the request message
* @param requestCallback callback to change message, can be <code>null</code>
* @param responseResult the result to write the response payload to
* @return <code>true</code> if a response was received; <code>false</code> otherwise
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
void sendAndReceive(Source requestPayload, WebServiceMessageCallback requestCallback, Result responseResult)
boolean sendAndReceive(Source requestPayload, WebServiceMessageCallback requestCallback, Result responseResult)
throws WebServiceClientException;
/**
@@ -207,12 +210,13 @@ public interface WebServiceOperations {
* @param requestPayload the payload of the request message
* @param requestCallback callback to change message, can be <code>null</code>
* @param responseResult the result to write the response payload to
* @return <code>true</code> if a response was received; <code>false</code> otherwise
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
void sendAndReceive(String uri,
Source requestPayload,
WebServiceMessageCallback requestCallback,
Result responseResult) throws WebServiceClientException;
boolean sendAndReceive(String uri,
Source requestPayload,
WebServiceMessageCallback requestCallback,
Result responseResult) throws WebServiceClientException;
/**
* Sends a web service message that can be manipulated with the given callback, reading the result with a
@@ -250,9 +254,10 @@ public interface WebServiceOperations {
*
* @param requestCallback the callback to be used for manipulating the request message
* @param responseCallback the callback to be used for manipulating the response message
* @return <code>true</code> if a response was received; <code>false</code> otherwise
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
void sendAndReceive(WebServiceMessageCallback requestCallback, WebServiceMessageCallback responseCallback)
boolean sendAndReceive(WebServiceMessageCallback requestCallback, WebServiceMessageCallback responseCallback)
throws WebServiceClientException;
/**
@@ -262,9 +267,10 @@ public interface WebServiceOperations {
* @param uri the URI to send the message to
* @param requestCallback the callback to be used for manipulating the request message
* @param responseCallback the callback to be used for manipulating the response message
* @return <code>true</code> if a response was received; <code>false</code> otherwise
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
void sendAndReceive(String uri,
WebServiceMessageCallback requestCallback,
WebServiceMessageCallback responseCallback) throws WebServiceClientException;
boolean sendAndReceive(String uri,
WebServiceMessageCallback requestCallback,
WebServiceMessageCallback responseCallback) throws WebServiceClientException;
}

View File

@@ -18,7 +18,6 @@ package org.springframework.ws.client.core;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
@@ -26,11 +25,7 @@ import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.oxm.Marshaller;
@@ -44,6 +39,7 @@ import org.springframework.ws.client.WebServiceIOException;
import org.springframework.ws.client.WebServiceTransformerException;
import org.springframework.ws.client.WebServiceTransportException;
import org.springframework.ws.client.support.WebServiceAccessor;
import org.springframework.ws.soap.client.core.SoapFaultMessageResolver;
import org.springframework.ws.transport.FaultAwareWebServiceConnection;
import org.springframework.ws.transport.TransportException;
import org.springframework.ws.transport.WebServiceConnection;
@@ -51,31 +47,35 @@ import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.ws.transport.context.DefaultTransportContext;
import org.springframework.ws.transport.context.TransportContext;
import org.springframework.ws.transport.context.TransportContextHolder;
import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender;
import org.springframework.ws.transport.support.DefaultStrategiesHelper;
/**
* <strong>The central class for client-side Web services.</strong> It provides a message-driven approach to sending and
* receiving {@link org.springframework.ws.WebServiceMessage} instances.
* receiving {@link WebServiceMessage} instances.
* <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.
* This template uses a {@link SoapFaultMessageResolver} to handle fault response messages. Another {@link
* FaultMessageResolver} can be defined with with {@link #setFaultMessageResolver(FaultMessageResolver)
* faultMessageResolver} property. If this property is set to <code>null</code>, no fault resolving is performed.
*
* @author Arjen Poutsma
*/
public class WebServiceTemplate extends WebServiceAccessor implements WebServiceOperations, ApplicationContextAware {
public class WebServiceTemplate extends WebServiceAccessor implements WebServiceOperations {
private Marshaller marshaller;
private Unmarshaller unmarshaller;
private FaultResolver faultResolver = new SimpleFaultResolver();
private FaultMessageResolver faultMessageResolver;
private String defaultUri;
/** Creates a new <code>WebServiceTemplate</code> using default settings. */
public WebServiceTemplate() {
initDefaultStrategies();
}
/**
@@ -84,7 +84,9 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
* @param messageFactory the message factory to use
*/
public WebServiceTemplate(WebServiceMessageFactory messageFactory) {
this();
setMessageFactory(messageFactory);
afterPropertiesSet();
}
/** Returns the default URI to be used on operations that do not have a URI parameter. */
@@ -104,7 +106,7 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
* @see #sendAndReceive(WebServiceMessageCallback,WebServiceMessageCallback)
*/
public void setDefaultUri(String uri) {
this.defaultUri = uri;
defaultUri = uri;
}
/** Returns the marshaller for this template. */
@@ -127,69 +129,60 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
this.unmarshaller = unmarshaller;
}
/** Returns the fault resolver for this template. */
public FaultResolver getFaultResolver() {
return faultResolver;
/** Returns the fault message resolver for this template. */
public FaultMessageResolver getFaultMessageResolver() {
return faultMessageResolver;
}
/** Sets the fault resolver for this template. */
public void setFaultResolver(FaultResolver faultResolver) {
Assert.notNull(faultResolver, "faultResolver must not be null");
this.faultResolver = faultResolver;
/**
* Sets the fault resolver for this template. Default is the {@link SimpleFaultMessageResolver}, but may be set to
* <code>null</code> to disable fault handling.
*/
public void setFaultMessageResolver(FaultMessageResolver faultMessageResolver) {
this.faultMessageResolver = faultMessageResolver;
}
public final void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
/**
* Initialize the default implementations for the template's strategies: {@link SoapFaultMessageResolver}, {@link
* org.springframework.ws.soap.saaj.SaajSoapMessageFactory}, and {@link HttpUrlConnectionMessageSender}.
*
* @throws BeanInitializationException in case of initalization errors
* @see #setFaultMessageResolver(FaultMessageResolver)
* @see #setMessageFactory(WebServiceMessageFactory)
* @see #setMessageSender(WebServiceMessageSender)
*/
protected void initDefaultStrategies() {
Resource resource = new ClassPathResource(ClassUtils.getShortName(getClass()) + ".properties", getClass());
DefaultStrategiesHelper defaultStrategiesHelper = new DefaultStrategiesHelper(resource);
DefaultStrategiesHelper strategiesHelper = new DefaultStrategiesHelper(resource);
if (getMessageFactory() == null) {
initWebServiceMessageFactory(defaultStrategiesHelper, applicationContext);
initMessageFactory(strategiesHelper);
}
if (ObjectUtils.isEmpty(getMessageSenders())) {
initWebServiceMessageSenders(defaultStrategiesHelper, applicationContext);
initMessageSenders(strategiesHelper);
}
if (getFaultMessageResolver() == null) {
initFaultMessageResolver(strategiesHelper);
}
}
private void initWebServiceMessageFactory(DefaultStrategiesHelper defaultStrategiesHelper,
ApplicationContext applicationContext)
throws BeanInitializationException {
WebServiceMessageFactory messageFactory = (WebServiceMessageFactory) defaultStrategiesHelper
.getDefaultStrategy(WebServiceMessageFactory.class, applicationContext);
if (logger.isInfoEnabled()) {
logger.info("Using default message factory [" + messageFactory + "]");
}
if (messageFactory instanceof InitializingBean) {
try {
((InitializingBean) messageFactory).afterPropertiesSet();
}
catch (Exception ex) {
throw new BeanInitializationException("Could not initialize message factory", ex);
}
}
private void initMessageFactory(DefaultStrategiesHelper helper) throws BeanInitializationException {
WebServiceMessageFactory messageFactory = (WebServiceMessageFactory) helper
.getDefaultStrategy(WebServiceMessageFactory.class);
setMessageFactory(messageFactory);
}
private void initWebServiceMessageSenders(DefaultStrategiesHelper defaultStrategiesHelper,
ApplicationContext applicationContext) {
List messageSenders =
defaultStrategiesHelper.getDefaultStrategies(WebServiceMessageSender.class, applicationContext);
if (logger.isInfoEnabled()) {
logger.info("Using default message senders " + messageSenders);
}
for (Iterator iterator = messageSenders.iterator(); iterator.hasNext();) {
WebServiceMessageSender messageSender = (WebServiceMessageSender) iterator.next();
if (messageSender instanceof InitializingBean) {
try {
((InitializingBean) messageSender).afterPropertiesSet();
}
catch (Exception ex) {
throw new BeanInitializationException("Could not initialize message factory", ex);
}
}
}
private void initMessageSenders(DefaultStrategiesHelper helper) {
List messageSenders = helper.getDefaultStrategies(WebServiceMessageSender.class);
setMessageSenders(
(WebServiceMessageSender[]) messageSenders.toArray(new WebServiceMessageSender[messageSenders.size()]));
}
private void initFaultMessageResolver(DefaultStrategiesHelper helper) throws BeanInitializationException {
FaultMessageResolver faultMessageResolver =
(FaultMessageResolver) helper.getDefaultStrategy(FaultMessageResolver.class);
setFaultMessageResolver(faultMessageResolver);
}
/*
* Marshalling methods
*/
@@ -217,10 +210,10 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
}
return sendAndReceive(uri, new WebServiceMessageCallback() {
public void doInMessage(WebServiceMessage message) throws IOException {
public void doWithMessage(WebServiceMessage message) throws IOException {
getMarshaller().marshal(requestPayload, message.getPayloadResult());
if (requestCallback != null) {
requestCallback.doInMessage(message);
requestCallback.doWithMessage(message);
}
}
}, new WebServiceMessageExtractor() {
@@ -235,38 +228,40 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
* Result-handling methods
*/
public void sendAndReceive(Source requestPayload, Result responseResult) {
sendAndReceive(requestPayload, null, responseResult);
public boolean sendAndReceive(Source requestPayload, Result responseResult) {
return sendAndReceive(requestPayload, null, responseResult);
}
public void sendAndReceive(String uri, Source requestPayload, Result responseResult) {
sendAndReceive(uri, requestPayload, null, responseResult);
public boolean sendAndReceive(String uri, Source requestPayload, Result responseResult) {
return sendAndReceive(uri, requestPayload, null, responseResult);
}
public void sendAndReceive(Source requestPayload,
WebServiceMessageCallback requestCallback,
final Result responseResult) {
sendAndReceive(getDefaultUri(), requestPayload, requestCallback, responseResult);
public boolean sendAndReceive(Source requestPayload,
WebServiceMessageCallback requestCallback,
final Result responseResult) {
return sendAndReceive(getDefaultUri(), requestPayload, requestCallback, responseResult);
}
public void sendAndReceive(String uri,
Source requestPayload,
WebServiceMessageCallback requestCallback,
final Result responseResult) {
public boolean sendAndReceive(String uri,
Source requestPayload,
WebServiceMessageCallback requestCallback,
final Result responseResult) {
try {
final Transformer transformer = createTransformer();
doSendAndReceive(uri, transformer, requestPayload, requestCallback, new SourceExtractor() {
Boolean retVal = (Boolean) doSendAndReceive(uri, transformer, requestPayload, requestCallback,
new SourceExtractor() {
public Object extractData(Source source) throws IOException {
try {
transformer.transform(source, responseResult);
}
catch (TransformerException ex) {
throw new WebServiceTransformerException("Could not transform payload", ex);
}
return null;
}
});
public Object extractData(Source source) throws IOException {
try {
transformer.transform(source, responseResult);
}
catch (TransformerException ex) {
throw new WebServiceTransformerException("Could not transform payload", ex);
}
return Boolean.TRUE;
}
});
return retVal != null && retVal.booleanValue();
}
catch (TransformerConfigurationException ex) {
throw new WebServiceTransformerException("Could not create transformer", ex);
@@ -311,11 +306,11 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
final SourceExtractor responseExtractor) {
Assert.notNull(responseExtractor, "responseExtractor must not be null");
return sendAndReceive(uri, new WebServiceMessageCallback() {
public void doInMessage(WebServiceMessage message) throws IOException {
public void doWithMessage(WebServiceMessage message) throws IOException {
try {
transformer.transform(requestPayload, message.getPayloadResult());
if (requestCallback != null) {
requestCallback.doInMessage(message);
requestCallback.doWithMessage(message);
}
}
catch (TransformerException ex) {
@@ -329,16 +324,18 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
* WebServiceMessage-handling methods
*/
public void sendAndReceive(WebServiceMessageCallback requestCallback, WebServiceMessageCallback responseCallback) {
Assert.notNull(responseCallback, "responseCallback must not be null");
sendAndReceive(requestCallback, new WebServiceMessageCallbackMessageExtractor(responseCallback));
public boolean sendAndReceive(WebServiceMessageCallback requestCallback,
WebServiceMessageCallback responseCallback) {
return sendAndReceive(getDefaultUri(), requestCallback, responseCallback);
}
public void sendAndReceive(String uri,
WebServiceMessageCallback requestCallback,
WebServiceMessageCallback responseCallback) {
public boolean sendAndReceive(String uri,
WebServiceMessageCallback requestCallback,
WebServiceMessageCallback responseCallback) {
Assert.notNull(responseCallback, "responseCallback must not be null");
sendAndReceive(uri, requestCallback, new WebServiceMessageCallbackMessageExtractor(responseCallback));
Boolean result = (Boolean) sendAndReceive(uri, requestCallback,
new WebServiceMessageCallbackMessageExtractor(responseCallback));
return result != null && result.booleanValue();
}
public Object sendAndReceive(WebServiceMessageCallback requestCallback,
@@ -358,21 +355,26 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
TransportContextHolder.setTransportContext(new DefaultTransportContext(connection));
WebServiceMessage request = getMessageFactory().createWebServiceMessage();
if (requestCallback != null) {
requestCallback.doInMessage(request);
requestCallback.doWithMessage(request);
}
sendRequest(connection, request);
WebServiceMessage response = receiveResponse(connection);
if (connection.hasError()) {
return handleError(connection, request);
}
WebServiceMessage response = connection.receive(getMessageFactory());
if (response != null) {
if (!hasFault(connection, response)) {
// normal response
return responseExtractor.extractData(response);
if (hasFault(connection, response)) {
return handleFault(connection, request, response);
}
else {
// fault response
getFaultResolver().resolveFault(response);
logResponse(request, response);
return responseExtractor.extractData(response);
}
}
return null;
else {
logger.debug("Received no response for request [" + request + "]");
return null;
}
}
catch (TransportException ex) {
throw new WebServiceTransportException("Could not use transport: " + ex.getMessage(), ex);
@@ -393,6 +395,63 @@ 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).
*
* @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
* @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();
}
}
/**
* Handles an error on the given connection. The default implementation throws a {@link
* WebServiceTransportException}.
*
* @param connection the erronous connection
* @param request the corresponding request message
* @return the object to be returned from {@link #sendAndReceive(String,WebServiceMessageCallback,
*WebServiceMessageExtractor)}, if any
*/
protected Object handleError(WebServiceConnection connection, WebServiceMessage request) throws IOException {
logger.debug("Received " + connection.getErrorMessage() + " error for request [" + request + "]");
throw new WebServiceTransportException(connection.getErrorMessage());
}
/**
* Handles an fault in the given response message. The default implementation invokes the {@link
* FaultMessageResolver fault resolver} if registered, or invokes {@link #handleError(WebServiceConnection,
*WebServiceMessage)} otherwise.
*
* @param connection the erronous connection
* @param request the corresponding request message
* @param response the fault response message
* @return the object to be returned from {@link #sendAndReceive(String,WebServiceMessageCallback,
*WebServiceMessageExtractor)}, if any
*/
protected Object handleFault(WebServiceConnection connection, WebServiceMessage request, WebServiceMessage response)
throws IOException {
if (getFaultMessageResolver() != null) {
logger.debug("Received Fault message for request [" + request + "]");
getFaultMessageResolver().resolveFault(response);
return null;
}
else {
return handleError(connection, request);
}
}
/** Sends the request in the given message context over the connection. */
private void sendRequest(WebServiceConnection connection, WebServiceMessage request) throws IOException {
if (logger.isTraceEnabled()) {
@@ -406,31 +465,17 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
connection.send(request);
}
private WebServiceMessage receiveResponse(WebServiceConnection connection) throws IOException {
WebServiceMessage response = connection.receive(getMessageFactory());
if (response != null) {
if (logger.isTraceEnabled()) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
response.writeTo(os);
logger.trace("WebServiceTemplate receives response [" + os.toString("UTF-8") + "]");
}
else if (logger.isDebugEnabled()) {
logger.debug("WebServiceTemplate receives response [" + response + "]");
}
private void logResponse(WebServiceMessage request, WebServiceMessage response) throws IOException {
if (logger.isTraceEnabled()) {
ByteArrayOutputStream requestStream = new ByteArrayOutputStream();
request.writeTo(requestStream);
ByteArrayOutputStream responseStream = new ByteArrayOutputStream();
response.writeTo(responseStream);
logger.trace("Received response [" + responseStream.toString("UTF-8") + "] for request [" +
requestStream.toString("UTF-8") + "]");
}
else if (logger.isDebugEnabled()) {
logger.debug("WebServiceTemplate receives no response");
}
return response;
}
/** Determines whether the given connection or message context has a fault. */
private boolean hasFault(WebServiceConnection connection, WebServiceMessage response) throws IOException {
if (connection instanceof FaultAwareWebServiceConnection) {
return ((FaultAwareWebServiceConnection) connection).hasFault();
}
else {
return response.hasFault();
logger.debug("Received response [" + response + "] for request [" + request + "]");
}
}
@@ -444,8 +489,8 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
}
public Object extractData(WebServiceMessage message) throws IOException {
callback.doInMessage(message);
return null;
callback.doWithMessage(message);
return Boolean.TRUE;
}
}

View File

@@ -18,10 +18,7 @@ package org.springframework.ws.client.core.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.util.Assert;
@@ -44,7 +41,7 @@ import org.springframework.ws.transport.WebServiceMessageSender;
* @see org.springframework.ws.client.core.WebServiceTemplate
* @see #setMarshaller(org.springframework.oxm.Marshaller)
*/
public abstract class WebServiceGatewaySupport implements InitializingBean, ApplicationContextAware {
public abstract class WebServiceGatewaySupport implements InitializingBean {
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
@@ -144,10 +141,6 @@ public abstract class WebServiceGatewaySupport implements InitializingBean, Appl
webServiceTemplate.setUnmarshaller(unmarshaller);
}
public final void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
webServiceTemplate.setApplicationContext(applicationContext);
}
public final void afterPropertiesSet() throws Exception {
webServiceTemplate.afterPropertiesSet();
initGateway();

View File

@@ -64,7 +64,7 @@ public abstract class WebServiceAccessor extends TransformerObjectSupport implem
*/
public void setMessageSender(WebServiceMessageSender messageSender) {
Assert.notNull(messageSender, "'messageSender' must not be null");
this.messageSenders = new WebServiceMessageSender[]{messageSender};
messageSenders = new WebServiceMessageSender[]{messageSender};
}
/**
@@ -79,7 +79,7 @@ public abstract class WebServiceAccessor extends TransformerObjectSupport implem
this.messageSenders = messageSenders;
}
public void afterPropertiesSet() throws Exception {
public void afterPropertiesSet() {
Assert.notNull(getMessageFactory(), "Property 'messageFactory' is required");
Assert.notEmpty(getMessageSenders(), "Property 'messageSenders' is required");
}

View File

@@ -26,9 +26,13 @@ import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.springframework.util.Assert;
import org.springframework.ws.pox.PoxMessage;
import org.springframework.ws.transport.TransportConstants;
import org.springframework.ws.transport.TransportOutputStream;
import org.springframework.xml.namespace.QNameUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Implementation of the <code>PoxMessage</code> interface that is based on a DOM Document.
@@ -38,25 +42,27 @@ import org.w3c.dom.Document;
*/
public class DomPoxMessage implements PoxMessage {
private static final String CONTENT_TYPE = "text/xml";
private final String contentType;
private final Document document;
private Transformer transformer;
private final Transformer transformer;
/**
* Constructs a new instance of the <code>DomPoxMessage</code> with the given document.
*
* @param document the document to base the message on
*/
public DomPoxMessage(Document document, Transformer transformer) {
public DomPoxMessage(Document document, Transformer transformer, String contentType) {
Assert.notNull(document, "'document' must not be null");
Assert.notNull(transformer, "'transformer' must not be null");
Assert.hasLength(contentType, "'contentType' must not be empty");
this.document = document;
this.transformer = transformer;
this.contentType = contentType;
}
/**
* Returns the document underlying this message.
*/
/** Returns the document underlying this message. */
public Document getDocument() {
return document;
}
@@ -77,11 +83,21 @@ public class DomPoxMessage implements PoxMessage {
return null;
}
public String toString() {
StringBuffer buffer = new StringBuffer("DomPoxMessage ");
Element root = document.getDocumentElement();
if (root != null) {
buffer.append(' ');
buffer.append(QNameUtils.getQNameForNode(root));
}
return buffer.toString();
}
public void writeTo(OutputStream outputStream) throws IOException {
try {
if (outputStream instanceof TransportOutputStream) {
TransportOutputStream transportOutputStream = (TransportOutputStream) outputStream;
transportOutputStream.addHeader("Content-Type", CONTENT_TYPE);
transportOutputStream.addHeader(TransportConstants.HEADER_CONTENT_TYPE, contentType);
}
transformer.transform(getPayloadSource(), new StreamResult(outputStream));
}

View File

@@ -22,57 +22,56 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.xml.transform.TransformerObjectSupport;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
/**
* Implementation of the {@link org.springframework.ws.WebServiceMessageFactory WebServiceMessageFactory} interinterface
* that creates a DOM PoxMessage.
* Implementation of the {@link WebServiceMessageFactory} interinterface that creates a {@link DomPoxMessage}.
*
* @author Arjen Poutsma
* @see org.springframework.ws.pox.dom.DomPoxMessage
*/
public class DomPoxMessageFactory implements WebServiceMessageFactory, InitializingBean {
public class DomPoxMessageFactory extends TransformerObjectSupport implements WebServiceMessageFactory {
private DocumentBuilderFactory documentBuilderFactory;
/** The default content type for the POX messages. */
public static final String DEFAULT_CONTENT_TYPE = "application/xml";
private boolean namespaceAware = true;
private DocumentBuilderFactory documentBuilderFactory =
documentBuilderFactory = DocumentBuilderFactory.newInstance();
private TransformerFactory transformerFactory;
private String contentType = DEFAULT_CONTENT_TYPE;
private boolean validating = false;
public DomPoxMessageFactory() {
documentBuilderFactory.setNamespaceAware(true);
documentBuilderFactory.setValidating(false);
}
/**
* Set whether or not the XML parser should be XML namespace aware. Default is <code>true</code>.
*/
/** Sets the content-type for the {@link DomPoxMessage}. */
public void setContentType(String contentType) {
Assert.hasLength(contentType, "'contentType' must not be empty");
this.contentType = contentType;
}
/** Set whether or not the XML parser should be XML namespace aware. Default is <code>true</code>. */
public void setNamespaceAware(boolean namespaceAware) {
this.namespaceAware = namespaceAware;
}
/**
* Set if the XML parser should validate the document. Default is <code>false</code>.
*/
public void setValidating(boolean validating) {
this.validating = validating;
}
public void afterPropertiesSet() throws Exception {
documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setValidating(validating);
documentBuilderFactory.setNamespaceAware(namespaceAware);
transformerFactory = TransformerFactory.newInstance();
}
/** Set if the XML parser should validate the document. Default is <code>false</code>. */
public void setValidating(boolean validating) {
documentBuilderFactory.setValidating(validating);
}
public WebServiceMessage createWebServiceMessage() {
try {
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document request = documentBuilder.newDocument();
return new DomPoxMessage(request, transformerFactory.newTransformer());
return new DomPoxMessage(request, createTransformer(), contentType);
}
catch (ParserConfigurationException ex) {
throw new DomPoxMessageException("Could not create message context", ex);
@@ -86,7 +85,7 @@ public class DomPoxMessageFactory implements WebServiceMessageFactory, Initializ
try {
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document request = documentBuilder.parse(inputStream);
return new DomPoxMessage(request, transformerFactory.newTransformer());
return new DomPoxMessage(request, createTransformer(), contentType);
}
catch (ParserConfigurationException ex) {
throw new DomPoxMessageException("Could not create message context", ex);

View File

@@ -51,22 +51,17 @@ import org.springframework.ws.transport.support.DefaultStrategiesHelper;
/**
* Central dispatcher for use within Spring-WS, dispatching Web service messages to registered endpoints.
* <p/>
* This dispatcher is quite similar to Spring MVCs {@link DispatcherServlet}. Just like its counterpart, this
* dispatcher is very flexible. This class is SOAP agnostic; in typical SOAP Web Services, the
* {@link SoapMessageDispatcher} subclass is used.
* <ul>
* <li>It can use any {@link EndpointMapping} implementation - whether standard, or provided as part of an
* application - to control the routing of request messages to endpoint objects. Endpoint mappings can be registered
* using the <code>endpointMappings</code> property.</li>
* <li>It can use any {@link EndpointAdapter}; this allows one to use any endpoint interface or form. Defaults to the
* {@link MessageEndpointAdapter} and {@link PayloadEndpointAdapter}, for {@link MessageEndpoint} and
* {@link PayloadEndpoint}, respectively, and the {@link MessageMethodEndpointAdapter} and
* {@link PayloadMethodEndpointAdapter}. Additional endpoint adapters can be added through the
* <code>endpointAdapters</code> property.</li>
* <li>Its exception resolution strategy can be specified via a {@link EndpointExceptionResolver}, for example mapping
* certain exceptions to SOAP Faults. Default is none. Additional exception resolvers can be added through the
* <code>endpointExceptionResolvers</code> property.</li>
* </ul>
* This dispatcher is quite similar to Spring MVCs {@link DispatcherServlet}. Just like its counterpart, this dispatcher
* is very flexible. This class is SOAP agnostic; in typical SOAP Web Services, the {@link SoapMessageDispatcher}
* subclass is used. <ul> <li>It can use any {@link EndpointMapping} implementation - whether standard, or provided as
* part of an application - to control the routing of request messages to endpoint objects. Endpoint mappings can be
* registered using the <code>endpointMappings</code> property.</li> <li>It can use any {@link EndpointAdapter}; this
* allows one to use any endpoint interface or form. Defaults to the {@link MessageEndpointAdapter} and {@link
* PayloadEndpointAdapter}, for {@link MessageEndpoint} and {@link PayloadEndpoint}, respectively, and the {@link
* MessageMethodEndpointAdapter} and {@link PayloadMethodEndpointAdapter}. Additional endpoint adapters can be added
* through the <code>endpointAdapters</code> property.</li> <li>Its exception resolution strategy can be specified via a
* {@link EndpointExceptionResolver}, for example mapping certain exceptions to SOAP Faults. Default is none. Additional
* exception resolvers can be added through the <code>endpointExceptionResolvers</code> property.</li> </ul>
*
* @author Arjen Poutsma
* @see EndpointMapping
@@ -358,8 +353,8 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa
else {
endpointAdapters =
defaultStrategiesHelper.getDefaultStrategies(EndpointAdapter.class, applicationContext);
if (logger.isInfoEnabled() && !endpointAdapters.isEmpty()) {
logger.info("No EndpointAdapters found, using defaults");
if (logger.isDebugEnabled()) {
logger.debug("No EndpointAdapters found, using defaults");
}
}
}
@@ -382,8 +377,8 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa
else {
endpointExceptionResolvers = defaultStrategiesHelper
.getDefaultStrategies(EndpointExceptionResolver.class, applicationContext);
if (logger.isInfoEnabled() && !endpointExceptionResolvers.isEmpty()) {
logger.info("No EndpointExceptionResolvers found, using defaults");
if (logger.isDebugEnabled()) {
logger.debug("No EndpointExceptionResolvers found, using defaults");
}
}
}
@@ -406,8 +401,8 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa
else {
endpointMappings = defaultStrategiesHelper
.getDefaultStrategies(EndpointMapping.class, applicationContext);
if (logger.isInfoEnabled() && !endpointMappings.isEmpty()) {
logger.info("No EndpointMappings found, using defaults");
if (logger.isDebugEnabled()) {
logger.debug("No EndpointMappings found, using defaults");
}
}
}

View File

@@ -54,7 +54,6 @@ public abstract class AbstractEndpointMapping extends ApplicationObjectSupport i
*/
public final void setDefaultEndpoint(Object defaultEndpoint) {
this.defaultEndpoint = defaultEndpoint;
logger.info("Default mapping to endpoint [" + this.defaultEndpoint + "]");
}
/**

View File

@@ -26,11 +26,7 @@ import javax.xml.namespace.QName;
*/
public interface SoapFault extends SoapElement {
/**
* Returns the fault code.
*
* @return a <code>QName</code> representing the fault code
*/
/** Returns the fault code. */
QName getFaultCode();
/**
@@ -39,14 +35,10 @@ public interface SoapFault extends SoapElement {
*/
String getFaultStringOrReason();
/**
* Returns the fault actor or role. For SOAP 1.1, this returns the actor. For SOAP 1.2, this returns the role.
*/
/** Returns the fault actor or role. For SOAP 1.1, this returns the actor. For SOAP 1.2, this returns the role. */
String getFaultActorOrRole();
/**
* Sets the fault actor. For SOAP 1.1, this sets the actor. For SOAP 1.2, this sets the role.
*/
/** Sets the fault actor. For SOAP 1.1, this sets the actor. For SOAP 1.2, this sets the role. */
void setFaultActorOrRole(String faultActor);
/**

View File

@@ -0,0 +1,67 @@
/*
* 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.soap.client;
import javax.xml.namespace.QName;
import org.springframework.ws.client.WebServiceFaultException;
import org.springframework.ws.soap.SoapBody;
import org.springframework.ws.soap.SoapFault;
import org.springframework.ws.soap.SoapMessage;
/**
* Thrown by <code>SoapFaultMessageResolver</code> when the response message has a fault.
*
* @author Arjen Poutsma
*/
public class SoapFaultClientException extends WebServiceFaultException {
private final SoapFault soapFault;
/**
* Create a new instance of the <code>SoapFaultClientException</code> class.
*
* @param faultMessage the fault message
*/
public SoapFaultClientException(SoapMessage faultMessage) {
super(faultMessage);
SoapBody body = faultMessage.getSoapBody();
soapFault = body != null ? body.getFault() : null;
}
/** Returns the {@link SoapFault}. */
public SoapFault getSoapFault() {
return soapFault;
}
/** Returns the fault code. */
public QName getFaultCode() {
return soapFault != null ? soapFault.getFaultCode() : null;
}
/**
* 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.
* <p/>
* Note that this message returns the same as {@link #getMessage()}.
*/
public String getFaultStringOrReason() {
return soapFault != null ? soapFault.getFaultStringOrReason() : null;
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.ws.client.core.support;
package org.springframework.ws.soap.client.core;
import java.io.IOException;
@@ -40,14 +40,12 @@ public class SoapActionCallback implements WebServiceMessageCallback {
private final String soapAction;
/**
* Create a new <code>SoapActionCallback</code> with the given string SOAPAction.
*/
/** Create a new <code>SoapActionCallback</code> with the given string SOAPAction. */
public SoapActionCallback(String soapAction) {
this.soapAction = soapAction;
}
public void doInMessage(WebServiceMessage message) throws IOException {
public void doWithMessage(WebServiceMessage message) throws IOException {
SoapMessage soapMessage = (SoapMessage) message;
soapMessage.setSoapAction(soapAction);
}

View File

@@ -0,0 +1,38 @@
/*
* 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.soap.client.core;
import java.io.IOException;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.core.FaultMessageResolver;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.client.SoapFaultClientException;
/**
* Simple fault resolver that simply throws a {@link SoapFaultClientException} when a fault occurs.
*
* @author Arjen Poutsma
* @see SoapFaultClientException
*/
public class SoapFaultMessageResolver implements FaultMessageResolver {
public void resolveFault(WebServiceMessage message) throws IOException {
SoapMessage soapMessage = (SoapMessage) message;
throw new SoapFaultClientException(soapMessage);
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Contains core classes for SOAP-specific client-side Spring-WS support.
</body>
</html>

View File

@@ -0,0 +1,5 @@
<html>
<body>
Contains classes for SOAP-specific client-side Spring-WS support.
</body>
</html>

View File

@@ -130,8 +130,8 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB
throw new SoapMessageCreationException("Could not create SAAJ MessageFactory: " + ex.getMessage(), ex);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Using MessageFactory class [" + messageFactory.getClass().getName() + "]");
if (logger.isTraceEnabled()) {
logger.trace("Using MessageFactory class [" + messageFactory.getClass().getName() + "]");
}
}

View File

@@ -19,15 +19,16 @@ package org.springframework.ws.transport;
import java.io.IOException;
/**
* Sub-interface of {@link WebServiceConnection} that is aware of any SOAP Faults received. Typically, fault detection
* is done by inspecting connection error codes, etc.
* 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.
*
* @author Arjen Poutsma
*/
public interface FaultAwareWebServiceConnection extends WebServiceConnection {
/**
* Indicates whether this connection has a SOAP Fault.
* Indicates whether this connection has a Fault.
*
* @return <code>true</code> if this connection has a fault; <code>false</code> otherwise.
*/

View File

@@ -50,6 +50,22 @@ public interface WebServiceConnection {
*/
WebServiceMessage receive(WebServiceMessageFactory messageFactory) throws IOException;
/**
* Indicates whether this connection has an error. Typically, error detection is done by inspecting connection error
* codes, etc.
*
* @return <code>true</code> if this connection has an error; <code>false</code> otherwise.
*/
boolean hasError() throws IOException;
/**
* Returns the error message.
*
* @return the connection error message, if any; returns <code>null</code> when no error is present
* @see #hasError()
*/
String getErrorMessage() throws IOException;
/**
* Closes this connection.
* <p/>

View File

@@ -39,7 +39,7 @@ public abstract class AbstractHttpSenderConnection extends AbstractSenderConnect
protected static final String ENCODING_GZIP = "gzip";
protected static final int HTTP_STATUS_INTERNAL_ERROR = 500;
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;
@@ -55,8 +55,13 @@ 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_ERROR;
return getResponseCode() == HTTP_STATUS_INTERNAL_SERVER_ERROR;
}
protected final InputStream getResponseInputStream() throws IOException {

View File

@@ -25,7 +25,6 @@ import java.util.Iterator;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.springframework.util.Assert;
@@ -57,6 +56,10 @@ public class CommonsHttpConnection extends AbstractHttpSenderConnection {
return postMethod;
}
public String getErrorMessage() throws IOException {
return postMethod.getStatusText();
}
public void close() throws IOException {
postMethod.releaseConnection();
}
@@ -96,11 +99,6 @@ public class CommonsHttpConnection extends AbstractHttpSenderConnection {
}
protected InputStream getRawResponseInputStream() throws IOException {
if (postMethod.getStatusCode() != HttpStatus.SC_INTERNAL_SERVER_ERROR &&
postMethod.getStatusCode() / 100 != 2) {
throw new HttpTransportException("Did not receive successful HTTP response: status code = " +
postMethod.getStatusCode() + ", status message = [" + postMethod.getStatusText() + "]");
}
return postMethod.getResponseBodyAsStream();
}

View File

@@ -65,12 +65,20 @@ public class HttpServletConnection extends AbstractReceiverConnection implements
public void endpointNotFound() {
endpointFound = false;
httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
getHttpServletResponse().setStatus(HttpServletResponse.SC_NOT_FOUND);
}
public boolean hasError() throws IOException {
return false;
}
public String getErrorMessage() throws IOException {
return null;
}
public void close() throws IOException {
if (!sentResponse && endpointFound) {
httpServletResponse.setStatus(HttpServletResponse.SC_ACCEPTED);
getHttpServletResponse().setStatus(HttpServletResponse.SC_ACCEPTED);
}
}
@@ -79,15 +87,15 @@ public class HttpServletConnection extends AbstractReceiverConnection implements
*/
protected Iterator getRequestHeaderNames() throws IOException {
return new EnumerationIterator(httpServletRequest.getHeaderNames());
return new EnumerationIterator(getHttpServletRequest().getHeaderNames());
}
protected Iterator getRequestHeaders(String name) throws IOException {
return new EnumerationIterator(httpServletRequest.getHeaders(name));
return new EnumerationIterator(getHttpServletRequest().getHeaders(name));
}
protected InputStream getRequestInputStream() throws IOException {
return httpServletRequest.getInputStream();
return getHttpServletRequest().getInputStream();
}
/*
@@ -95,20 +103,20 @@ public class HttpServletConnection extends AbstractReceiverConnection implements
*/
protected void addResponseHeader(String name, String value) throws IOException {
httpServletResponse.addHeader(name, value);
getHttpServletResponse().addHeader(name, value);
}
protected OutputStream getResponseOutputStream() throws IOException {
return httpServletResponse.getOutputStream();
return getHttpServletResponse().getOutputStream();
}
protected void onSendBeforeWrite(WebServiceMessage message) throws IOException {
sentResponse = true;
if (!message.hasFault()) {
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
getHttpServletResponse().setStatus(HttpServletResponse.SC_OK);
}
else {
httpServletResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
getHttpServletResponse().setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
}

View File

@@ -58,6 +58,10 @@ public class HttpUrlConnection extends AbstractHttpSenderConnection {
connection.disconnect();
}
public String getErrorMessage() throws IOException {
return connection.getResponseMessage();
}
/*
* Sending request
*/
@@ -113,15 +117,11 @@ public class HttpUrlConnection extends AbstractHttpSenderConnection {
}
protected InputStream getRawResponseInputStream() throws IOException {
if (connection.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR) {
if (connection.getResponseCode() / 100 != 2) {
return connection.getErrorStream();
}
else if (connection.getResponseCode() / 100 == 2) {
return connection.getInputStream();
}
else {
throw new HttpTransportException("Did not receive successful HTTP response: status code = " +
connection.getResponseCode() + ", status message = [" + connection.getResponseMessage() + "]");
return connection.getInputStream();
}
}
}

View File

@@ -25,7 +25,6 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.servlet.DispatcherServlet;
@@ -42,24 +41,20 @@ import org.springframework.ws.wsdl.WsdlDefinition;
/**
* Servlet for simplified dispatching of Web service messages.
*
* <p>This servlet is a convenient alternative to the standard Spring-MVC
* {@link DispatcherServlet} with separate
* {@link WebServiceMessageReceiverHandlerAdapter}, {@link MessageDispatcher}, and
* {@link WsdlDefinitionHandlerAdapter} instances.
*
* <p>This servlet automatically detects {@link EndpointAdapter EndpointAdapters},
* {@link EndpointMapping EndpointMappings}, and
* {@link EndpointExceptionResolver EndpointExceptionResolvers} by type.
*
* <p>This servlet also automatically detects any {@link WsdlDefinition} in its
* application context. This WSDL is exposed under the bean name: for example, a
* {@link WsdlDefinition} bean named '<code>echo</code>' will be exposed as
* <code>echo.wsdl</code> in this servlet's context:
* <code>http://localhost:8080/spring-ws/echo.wsdl</code>. When the
* <code>transformWsdlLocations</code> init-param is set to <code>true</code> in
* this servlet's configuration in <code>web.xml</code>, all <code>location</code>
* attributes in the WSDL definitions will reflect the URL of the incoming request.
* <p/>
* <p>This servlet is a convenient alternative to the standard Spring-MVC {@link DispatcherServlet} with separate {@link
* WebServiceMessageReceiverHandlerAdapter}, {@link MessageDispatcher}, and {@link WsdlDefinitionHandlerAdapter}
* instances.
* <p/>
* <p>This servlet automatically detects {@link EndpointAdapter EndpointAdapters}, {@link EndpointMapping
* EndpointMappings}, and {@link EndpointExceptionResolver EndpointExceptionResolvers} by type.
* <p/>
* <p>This servlet also automatically detects any {@link WsdlDefinition} in its application context. This WSDL is
* exposed under the bean name: for example, a {@link WsdlDefinition} bean named '<code>echo</code>' will be exposed as
* <code>echo.wsdl</code> in this servlet's context: <code>http://localhost:8080/spring-ws/echo.wsdl</code>. When the
* <code>transformWsdlLocations</code> init-param is set to <code>true</code> in this servlet's configuration in
* <code>web.xml</code>, all <code>location</code> attributes in the WSDL definitions will reflect the URL of the
* incoming request.
*
* @author Arjen Poutsma
* @see org.springframework.web.servlet.DispatcherServlet
@@ -75,8 +70,8 @@ public class MessageDispatcherServlet extends FrameworkServlet {
public static final String MESSAGE_RECEIVER_BEAN_NAME = "messageReceiver";
/**
* Name of the class path resource (relative to the {@link MessageDispatcherServlet}
* class) that defines <code>MessageDispatcherServlet's</code> default strategy names.
* Name of the class path resource (relative to the {@link MessageDispatcherServlet} class) that defines
* <code>MessageDispatcherServlet's</code> default strategy names.
*/
private static final String DEFAULT_STRATEGIES_PATH = "MessageDispatcherServlet.properties";
@@ -102,14 +97,13 @@ public class MessageDispatcherServlet extends FrameworkServlet {
/** Public constructor, necessary for some Web application servers. */
public MessageDispatcherServlet() {
this.defaultStrategiesHelper = new DefaultStrategiesHelper(
defaultStrategiesHelper = new DefaultStrategiesHelper(
new ClassPathResource(DEFAULT_STRATEGIES_PATH, MessageDispatcherServlet.class));
}
/**
* Sets whether relative address locations in the WSDL are to be transformed using
* the request URI of the incoming {@link HttpServletRequest}.
* <p>Defaults to <code>false</code>.
* Sets whether relative address locations in the WSDL are to be transformed using the request URI of the incoming
* {@link HttpServletRequest}. <p>Defaults to <code>false</code>.
*/
public void setTransformWsdlLocations(boolean transformWsdlLocations) {
this.transformWsdlLocations = transformWsdlLocations;
@@ -129,10 +123,10 @@ public class MessageDispatcherServlet extends FrameworkServlet {
protected long getLastModified(HttpServletRequest httpServletRequest) {
WsdlDefinition definition = getWsdlDefinition(httpServletRequest);
if (definition != null) {
return this.wsdlDefinitionHandlerAdapter.getLastModified(httpServletRequest, definition);
return wsdlDefinitionHandlerAdapter.getLastModified(httpServletRequest, definition);
}
else {
return this.messageReceiverHandlerAdapter.getLastModified(httpServletRequest, this.messageReceiver);
return messageReceiverHandlerAdapter.getLastModified(httpServletRequest, messageReceiver);
}
}
@@ -140,27 +134,27 @@ public class MessageDispatcherServlet extends FrameworkServlet {
throws Exception {
WsdlDefinition definition = getWsdlDefinition(httpServletRequest);
if (definition != null) {
this.wsdlDefinitionHandlerAdapter.handle(httpServletRequest, httpServletResponse, definition);
wsdlDefinitionHandlerAdapter.handle(httpServletRequest, httpServletResponse, definition);
}
else {
this.messageReceiverHandlerAdapter.handle(httpServletRequest, httpServletResponse, this.messageReceiver);
messageReceiverHandlerAdapter.handle(httpServletRequest, httpServletResponse, messageReceiver);
}
}
/**
* Determines the {@link WsdlDefinition} for a given request, or <code>null</code>
* if none is found.
* Determines the {@link WsdlDefinition} for a given request, or <code>null</code> if none is found.
* <p/>
* Default implementation checks whether the request method is <code>GET</code>,
* whether the request uri ends with <code>".wsdl"</code>, and if there is a
* <code>WsdlDefinition</code> with the same name as the filename in the request uri.
* Default implementation checks whether the request method is <code>GET</code>, whether the request uri ends with
* <code>".wsdl"</code>, and if there is a <code>WsdlDefinition</code> with the same name as the filename in the
* request uri.
*
* @param request the <code>HttpServletRequest</code>
* @return a definition, or <code>null</code>
*/
protected WsdlDefinition getWsdlDefinition(HttpServletRequest request) {
if ("GET".equals(request.getMethod()) && request.getRequestURI().endsWith(WSDL_SUFFIX_NAME)) {
String fileName = WebUtils.extractFilenameFromUrlPath(request.getRequestURI());
return (WsdlDefinition) this.wsdlDefinitions.get(fileName);
return (WsdlDefinition) wsdlDefinitions.get(fileName);
}
else {
return null;
@@ -170,13 +164,13 @@ public class MessageDispatcherServlet extends FrameworkServlet {
private void initHandlerAdapters() throws BeansException {
try {
// setup the receiver adapter
this.messageReceiverHandlerAdapter = new WebServiceMessageReceiverHandlerAdapter();
messageReceiverHandlerAdapter = new WebServiceMessageReceiverHandlerAdapter();
initWebServiceMessageFactory();
this.messageReceiverHandlerAdapter.afterPropertiesSet();
messageReceiverHandlerAdapter.afterPropertiesSet();
// setup the wsdl adapter
this.wsdlDefinitionHandlerAdapter = new WsdlDefinitionHandlerAdapter();
this.wsdlDefinitionHandlerAdapter.setTransformLocations(this.transformWsdlLocations);
this.wsdlDefinitionHandlerAdapter.afterPropertiesSet();
wsdlDefinitionHandlerAdapter = new WsdlDefinitionHandlerAdapter();
wsdlDefinitionHandlerAdapter.setTransformLocations(transformWsdlLocations);
wsdlDefinitionHandlerAdapter.afterPropertiesSet();
}
catch (Exception ex) {
throw new BeanInitializationException("Could not initialize handler adapters", ex);
@@ -190,43 +184,35 @@ public class MessageDispatcherServlet extends FrameworkServlet {
.getBean(WEB_SERVICE_MESSAGE_FACTORY_BEAN_NAME, WebServiceMessageFactory.class);
}
catch (NoSuchBeanDefinitionException ignored) {
messageFactory = (WebServiceMessageFactory) this.defaultStrategiesHelper
messageFactory = (WebServiceMessageFactory) defaultStrategiesHelper
.getDefaultStrategy(WebServiceMessageFactory.class, getWebApplicationContext());
if (this.logger.isInfoEnabled()) {
this.logger.info("Unable to locate WebServiceMessageFactory with name '" +
WEB_SERVICE_MESSAGE_FACTORY_BEAN_NAME + "': using default [" + messageFactory + "]");
}
if (messageFactory instanceof InitializingBean) {
((InitializingBean) messageFactory).afterPropertiesSet();
if (logger.isDebugEnabled()) {
logger.debug("No WebServiceMessageFactory found in servlet '" + getServletName() + "': using default");
}
}
this.messageReceiverHandlerAdapter.setMessageFactory(messageFactory);
messageReceiverHandlerAdapter.setMessageFactory(messageFactory);
}
private void initMessageReceiver() {
try {
this.messageReceiver = (WebServiceMessageReceiver) getWebApplicationContext()
messageReceiver = (WebServiceMessageReceiver) getWebApplicationContext()
.getBean(MESSAGE_RECEIVER_BEAN_NAME, WebServiceMessageReceiver.class);
}
catch (NoSuchBeanDefinitionException ex) {
this.messageReceiver = (WebServiceMessageReceiver) this.defaultStrategiesHelper
messageReceiver = (WebServiceMessageReceiver) defaultStrategiesHelper
.getDefaultStrategy(WebServiceMessageReceiver.class, getWebApplicationContext());
if (this.messageReceiver instanceof BeanNameAware) {
((BeanNameAware) this.messageReceiver).setBeanName(getServletName());
if (messageReceiver instanceof BeanNameAware) {
((BeanNameAware) messageReceiver).setBeanName(getServletName());
}
if (this.logger.isInfoEnabled()) {
this.logger.info("Unable to locate MessageDispatcher with name '" + MESSAGE_RECEIVER_BEAN_NAME +
"': using default [" + this.messageReceiver + "]");
if (logger.isDebugEnabled()) {
logger.debug("No MessageDispatcher found in servlet '" + getServletName() + "': using default");
}
}
}
/**
* Find all {@link WsdlDefinition WsdlDefinitions} in the ApplicationContext,
* incuding ancestor contexts.
*/
/** Find all {@link WsdlDefinition WsdlDefinitions} in the ApplicationContext, incuding ancestor contexts. */
private void initWsdlDefinitions() {
this.wsdlDefinitions = BeanFactoryUtils
wsdlDefinitions = BeanFactoryUtils
.beansOfTypeIncludingAncestors(getWebApplicationContext(), WsdlDefinition.class, true, false);
}
}

View File

@@ -22,20 +22,36 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import javax.servlet.ServletContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.context.WebApplicationContext;
/**
* Helper class for for loading default implementations of an interface. Encapsulates a properties object, which
* contains strategy interface names as keys, and comma-separated class names as values.
* <p/>
* Simulates the {@link BeanFactory normal lifecycle} for beans, by calling {@link
* BeanFactoryAware#setBeanFactory(BeanFactory)}, {@link ApplicationContextAware#setApplicationContext(ApplicationContext)},
* etc.
*
* @author Arjen Poutsma
*/
@@ -68,12 +84,25 @@ public class DefaultStrategiesHelper {
}
/**
* Create a list of strategy objects for the given strategy interface. Strategies are retrieved from the given
* <code>Properties</code> object. It instantiates the strategy objects and satisifies
* Create a list of strategy objects for the given strategy interface. Strategies are retrieved from the
* <code>Properties</code> object given at construction-time.
*
* @param strategyInterface the strategy interface
* @return a list of corresponding strategy objects
* @throws BeansException if initialization failed
*/
public List getDefaultStrategies(Class strategyInterface) throws BeanInitializationException {
return getDefaultStrategies(strategyInterface, null);
}
/**
* Create a list of strategy objects for the given strategy interface. Strategies are retrieved from the
* <code>Properties</code> object given at construction-time. It instantiates the strategy objects and satisifies
* <code>ApplicationContextAware</code> with the supplied context if necessary.
*
* @param strategyInterface the strategy interface
* @param applicationContext used to satisfy strategies that are application context aware
* @param applicationContext used to satisfy strategies that are application context aware, may be
* <code>null</code>
* @return a list of corresponding strategy objects
* @throws BeansException if initialization failed
*/
@@ -88,10 +117,7 @@ public class DefaultStrategiesHelper {
result = new ArrayList(classNames.length);
for (int i = 0; i < classNames.length; i++) {
Class clazz = ClassUtils.forName(classNames[i]);
Object strategy = BeanUtils.instantiateClass(clazz);
if (strategy instanceof ApplicationContextAware) {
((ApplicationContextAware) strategy).setApplicationContext(applicationContext);
}
Object strategy = instantiateBean(clazz, applicationContext);
result.add(strategy);
}
}
@@ -104,18 +130,75 @@ public class DefaultStrategiesHelper {
throw new BeanInitializationException("Could not find default strategy class for interface [" + key + "]",
ex);
}
}
/** Instantiates the given bean, simulating the standard bean lifecycle. */
private Object instantiateBean(Class clazz, ApplicationContext applicationContext) {
Object strategy = BeanUtils.instantiateClass(clazz);
if (strategy instanceof BeanNameAware) {
BeanNameAware beanNameAware = (BeanNameAware) strategy;
beanNameAware.setBeanName(clazz.getName());
}
if (applicationContext != null) {
if (strategy instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) strategy).setBeanClassLoader(applicationContext.getClassLoader());
}
if (strategy instanceof BeanFactoryAware) {
((BeanFactoryAware) strategy).setBeanFactory(applicationContext);
}
if (strategy instanceof ResourceLoaderAware) {
((ResourceLoaderAware) strategy).setResourceLoader(applicationContext);
}
if (strategy instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) strategy).setApplicationEventPublisher(applicationContext);
}
if (strategy instanceof MessageSourceAware) {
((MessageSourceAware) strategy).setMessageSource(applicationContext);
}
if (strategy instanceof ApplicationContextAware) {
ApplicationContextAware applicationContextAware = (ApplicationContextAware) strategy;
applicationContextAware.setApplicationContext(applicationContext);
}
if (applicationContext instanceof WebApplicationContext && strategy instanceof ServletContextAware) {
ServletContext servletContext = ((WebApplicationContext) applicationContext).getServletContext();
((ServletContextAware) strategy).setServletContext(servletContext);
}
}
if (strategy instanceof InitializingBean) {
InitializingBean initializingBean = (InitializingBean) strategy;
try {
initializingBean.afterPropertiesSet();
}
catch (Throwable ex) {
throw new BeanCreationException("Invocation of init method failed", ex);
}
}
return strategy;
}
/**
* Return the default strategy object for the given strategy interface. <p>Delegates to
* <code>getDefaultStrategies</code>, expecting a single object in the list.
* Return the default strategy object for the given strategy interface.
*
* @param strategyInterface the strategy interface
* @return the corresponding strategy object
* @throws BeansException if initialization failed
* @see #getDefaultStrategies
*/
public Object getDefaultStrategy(Class strategyInterface) throws BeanInitializationException {
return getDefaultStrategy(strategyInterface, null);
}
/**
* Return the default strategy object for the given strategy interface.
* <p/>
* Delegates to {@link #getDefaultStrategies(Class,ApplicationContext)}, expecting a single object in the list.
*
* @param strategyInterface the strategy interface
* @param applicationContext used to satisfy strategies that are application context aware, may be
* <code>null</code>
* @return the corresponding strategy object
* @throws BeansException if initialization failed
*/
public Object getDefaultStrategy(Class strategyInterface, ApplicationContext applicationContext)
throws BeanInitializationException {
List result = getDefaultStrategies(strategyInterface, applicationContext);

View File

@@ -60,7 +60,6 @@ public abstract class WebServiceMessageReceiverObjectSupport implements Initiali
public void afterPropertiesSet() throws Exception {
Assert.notNull(messageFactory, "messageFactory is required");
logger.info("Using message factory [" + messageFactory + "]");
}
/**

View File

@@ -1,5 +1,5 @@
# Default implementation classes for WebServiceTemplate's strategy interfaces.
# Not meant to be customized by application developers.
org.springframework.ws.client.core.FaultMessageResolver=org.springframework.ws.soap.client.core.SoapFaultMessageResolver
org.springframework.ws.WebServiceMessageFactory=org.springframework.ws.soap.saaj.SaajSoapMessageFactory
org.springframework.ws.transport.WebServiceMessageSender=org.springframework.ws.transport.http.HttpUrlConnectionMessageSender

View File

@@ -21,12 +21,12 @@ import org.easymock.MockControl;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.WebServiceFaultException;
public class SimpleFaultResolverTest extends TestCase {
public class SimpleFaultMessageResolverTest extends TestCase {
private SimpleFaultResolver resolver;
private SimpleFaultMessageResolver resolver;
protected void setUp() throws Exception {
resolver = new SimpleFaultResolver();
resolver = new SimpleFaultMessageResolver();
}
public void testResolveFault() throws Exception {

View File

@@ -31,6 +31,8 @@ import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import org.springframework.util.StringUtils;
/**
* A simple Servlet that uses SAAJ to echo request.
*
@@ -53,52 +55,32 @@ public class SimpleSaajServlet extends HttpServlet {
private MimeHeaders getHeaders(HttpServletRequest httpServletRequest) {
Enumeration enumeration = httpServletRequest.getHeaderNames();
MimeHeaders headers = new MimeHeaders();
while (enumeration.hasMoreElements()) {
String headerName = (String) enumeration.nextElement();
String headerValue = httpServletRequest.getHeader(headerName);
StringTokenizer values = new StringTokenizer(headerValue, ",");
while (values.hasMoreTokens()) {
headers.addHeader(headerName, values.nextToken().trim());
}
}
return headers;
}
private void putHeaders(MimeHeaders headers, HttpServletResponse res) {
Iterator it = headers.getAllHeaders();
while (it.hasNext()) {
MimeHeader header = (MimeHeader) it.next();
String[] values = headers.getHeader(header.getName());
if (values.length == 1) {
res.setHeader(header.getName(), header.getValue());
}
else {
StringBuffer concat = new StringBuffer();
int i = 0;
while (i < values.length) {
if (i != 0) {
concat.append(',');
}
concat.append(values[i++]);
}
res.setHeader(header.getName(), concat.toString());
}
String value = StringUtils.arrayToCommaDelimitedString(values);
res.setHeader(header.getName(), value);
}
}
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
MimeHeaders headers = getHeaders(req);
SOAPMessage msg = msgFactory.createMessage(headers, req.getInputStream());
SOAPMessage reply = onMessage(msg);
SOAPMessage request = msgFactory.createMessage(headers, req.getInputStream());
SOAPMessage reply = onMessage(request);
if (reply != null) {
if (reply.saveRequired()) {
reply.saveChanges();
@@ -117,7 +99,7 @@ public class SimpleSaajServlet extends HttpServlet {
}
}
public SOAPMessage onMessage(SOAPMessage message) {
protected SOAPMessage onMessage(SOAPMessage message) {
return message;
}

View File

@@ -16,16 +16,47 @@
package org.springframework.ws.client.core;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.StringTokenizer;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.custommonkey.xmlunit.XMLTestCase;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
import org.springframework.util.StringUtils;
import org.springframework.ws.client.WebServiceTransportException;
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.HttpUrlConnectionMessageSender;
import org.springframework.ws.transport.http.CommonsHttpMessageSender;
import org.springframework.xml.transform.StringResult;
import org.springframework.xml.transform.StringSource;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
public class WebServiceTemplateIntegrationTest extends XMLTestCase {
@@ -36,31 +67,207 @@ public class WebServiceTemplateIntegrationTest extends XMLTestCase {
protected void setUp() throws Exception {
jettyServer = new Server(8888);
Context jettyContext = new Context(jettyServer, "/");
jettyContext.addServlet(SimpleSaajServlet.class, "/");
jettyContext.addServlet(new ServletHolder(new EchoSoapServlet()), "/soap/echo");
jettyContext.addServlet(new ServletHolder(new SoapFaultServlet()), "/soap/fault");
jettyContext.addServlet(new ServletHolder(new NoResponseSoapServlet()), "/soap/noResponse");
jettyContext.addServlet(new ServletHolder(new PoxServlet()), "/pox");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(404)), "/errors/notfound");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(500)), "/errors/server");
jettyServer.start();
template = new WebServiceTemplate();
template.setDefaultUri("http://localhost:8888/");
template.setMessageSender(new HttpUrlConnectionMessageSender());
template.setMessageSender(new CommonsHttpMessageSender());
template.setFaultMessageResolver(new SoapFaultMessageResolver());
}
protected void tearDown() throws Exception {
jettyServer.stop();
}
public void testSendAndReceiveSaaj() throws Exception {
template.setMessageFactory(new SaajSoapMessageFactory(MessageFactory.newInstance()));
String content = "<root xmlns='http://springframework.org/spring-ws'><child/></root>";
StringResult result = new StringResult();
template.sendAndReceive(new StringSource(content), result);
assertXMLEqual(content, result.toString());
public void testAxiom() throws Exception {
testSoap(new AxiomSoapMessageFactory());
}
public void testSendAndReceiveAxiom() throws Exception {
template.setMessageFactory(new AxiomSoapMessageFactory());
public void testPox() throws Exception {
template.setMessageFactory(new DomPoxMessageFactory());
template.setFaultMessageResolver(null);
String content = "<root xmlns='http://springframework.org/spring-ws'><child/></root>";
StringResult result = new StringResult();
template.sendAndReceive(new StringSource(content), result);
template.sendAndReceive("http://localhost:8888/pox", new StringSource(content), result);
assertXMLEqual(content, result.toString());
try {
template.sendAndReceive("http://localhost:8888/errors/notfound", new StringSource(content),
new StringResult());
fail("WebServiceTransportException expected");
}
catch (WebServiceTransportException ex) {
//expected
}
try {
template.sendAndReceive("http://localhost:8888/errors/server", new StringSource(content), result);
fail("WebServiceTransportException expected");
}
catch (WebServiceTransportException ex) {
//expected
}
}
public void testWithSaaj() throws Exception {
testSoap(new SaajSoapMessageFactory(MessageFactory.newInstance()));
}
private void testSoap(SoapMessageFactory messageFactory)
throws SAXException, IOException, ParserConfigurationException {
template.setMessageFactory(messageFactory);
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);
assertXMLEqual(content, result.toString());
boolean b = template.sendAndReceive("http://localhost:8888/soap/noResponse", new StringSource(content),
new StringResult());
assertFalse("Invalid result", b);
try {
template.sendAndReceive("http://localhost:8888/errors/notfound", new StringSource(content),
new StringResult());
fail("WebServiceTransportException expected");
}
catch (WebServiceTransportException ex) {
//expected
}
try {
template.sendAndReceive("http://localhost:8888/soap/fault", new StringSource(content), result);
fail("SoapFaultClientException expected");
}
catch (SoapFaultClientException ex) {
//expected
}
}
/** Servlet that returns and error message for a given status code. */
private static class ErrorServlet extends HttpServlet {
private int sc;
public ErrorServlet(int sc) {
this.sc = sc;
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendError(sc);
}
}
/** Simple POX Servlet. */
private static class PoxServlet extends HttpServlet {
private DocumentBuilderFactory documentBuilderFactory;
private TransformerFactory transformerFactory;
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
transformerFactory = TransformerFactory.newInstance();
}
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document message = documentBuilder.parse(req.getInputStream());
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(message), new StreamResult(resp.getOutputStream()));
}
catch (Exception ex) {
throw new ServletException("POX POST failed" + ex.getMessage());
}
}
}
/** Abstract SOAP Servlet */
private abstract static class AbstractSoapServlet extends HttpServlet {
protected MessageFactory msgFactory = null;
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
try {
msgFactory = MessageFactory.newInstance();
}
catch (SOAPException ex) {
throw new ServletException("Unable to create message factory" + ex.getMessage());
}
}
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
MimeHeaders headers = getHeaders(req);
SOAPMessage request = msgFactory.createMessage(headers, req.getInputStream());
SOAPMessage reply = onMessage(request);
if (reply != null) {
if (reply.saveRequired()) {
reply.saveChanges();
}
resp.setStatus(!reply.getSOAPBody().hasFault() ? HttpServletResponse.SC_OK :
HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
putHeaders(reply.getMimeHeaders(), resp);
reply.writeTo(resp.getOutputStream());
}
else {
resp.setStatus(HttpServletResponse.SC_ACCEPTED);
}
}
catch (Exception ex) {
throw new ServletException("SAAJ POST failed " + ex.getMessage());
}
}
private MimeHeaders getHeaders(HttpServletRequest httpServletRequest) {
Enumeration enumeration = httpServletRequest.getHeaderNames();
MimeHeaders headers = new MimeHeaders();
while (enumeration.hasMoreElements()) {
String headerName = (String) enumeration.nextElement();
String headerValue = httpServletRequest.getHeader(headerName);
StringTokenizer values = new StringTokenizer(headerValue, ",");
while (values.hasMoreTokens()) {
headers.addHeader(headerName, values.nextToken().trim());
}
}
return headers;
}
private void putHeaders(MimeHeaders headers, HttpServletResponse res) {
Iterator it = headers.getAllHeaders();
while (it.hasNext()) {
MimeHeader header = (MimeHeader) it.next();
String[] values = headers.getHeader(header.getName());
res.setHeader(header.getName(), StringUtils.arrayToCommaDelimitedString(values));
}
}
protected abstract SOAPMessage onMessage(SOAPMessage message) throws SOAPException;
}
private static class EchoSoapServlet extends AbstractSoapServlet {
protected SOAPMessage onMessage(SOAPMessage message) throws SOAPException {
return message;
}
}
private static class NoResponseSoapServlet extends AbstractSoapServlet {
protected SOAPMessage onMessage(SOAPMessage message) throws SOAPException {
return null;
}
}
private static class SoapFaultServlet extends AbstractSoapServlet {
protected SOAPMessage onMessage(SOAPMessage message) throws SOAPException {
SOAPMessage response = msgFactory.createMessage();
SOAPBody body = response.getSOAPBody();
body.addFault(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Server"), "Server fault");
return response;
}
}
}

View File

@@ -25,6 +25,7 @@ import org.springframework.oxm.Unmarshaller;
import org.springframework.ws.MockWebServiceMessage;
import org.springframework.ws.MockWebServiceMessageFactory;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.WebServiceTransportException;
import org.springframework.ws.transport.FaultAwareWebServiceConnection;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.WebServiceMessageSender;
@@ -89,7 +90,7 @@ public class WebServiceTemplateTest extends XMLTestCase {
public void testSendAndReceiveMessageResponse() throws Exception {
MockControl callbackControl = MockControl.createControl(WebServiceMessageCallback.class);
WebServiceMessageCallback requestCallback = (WebServiceMessageCallback) callbackControl.getMock();
requestCallback.doInMessage(null);
requestCallback.doWithMessage(null);
callbackControl.setMatcher(MockControl.ALWAYS_MATCHER);
callbackControl.replay();
@@ -103,6 +104,7 @@ public class WebServiceTemplateTest extends XMLTestCase {
connectionMock.send(null);
connectionControl.setMatcher(MockControl.ALWAYS_MATCHER);
connectionControl.expectAndReturn(connectionMock.hasError(), false);
connectionControl
.expectAndReturn(connectionMock.receive(messageFactory), new MockWebServiceMessage("<response/>"));
connectionControl.expectAndReturn(connectionMock.hasFault(), false);
@@ -119,59 +121,76 @@ public class WebServiceTemplateTest extends XMLTestCase {
}
public void testSendAndReceiveMessageNoResponse() throws Exception {
MockControl callbackControl = MockControl.createControl(WebServiceMessageCallback.class);
WebServiceMessageCallback requestCallback = (WebServiceMessageCallback) callbackControl.getMock();
requestCallback.doInMessage(null);
callbackControl.setMatcher(MockControl.ALWAYS_MATCHER);
callbackControl.replay();
MockControl extractorControl = MockControl.createControl(WebServiceMessageExtractor.class);
WebServiceMessageExtractor extractorMock = (WebServiceMessageExtractor) extractorControl.getMock();
extractorControl.replay();
connectionMock.send(null);
connectionControl.setMatcher(MockControl.ALWAYS_MATCHER);
connectionControl.expectAndReturn(connectionMock.hasError(), false);
connectionControl.expectAndReturn(connectionMock.receive(messageFactory), null);
connectionMock.close();
connectionControl.replay();
Object result = (WebServiceMessage) template.sendAndReceive(requestCallback, extractorMock);
Object result = (WebServiceMessage) template.sendAndReceive(null, extractorMock);
assertNull("Invalid response", result);
callbackControl.verify();
extractorControl.verify();
connectionControl.verify();
}
public void testSendAndReceiveMessageFault() throws Exception {
MockControl callbackControl = MockControl.createControl(WebServiceMessageCallback.class);
WebServiceMessageCallback requestCallback = (WebServiceMessageCallback) callbackControl.getMock();
requestCallback.doInMessage(null);
callbackControl.setMatcher(MockControl.ALWAYS_MATCHER);
callbackControl.replay();
MockControl extractorControl = MockControl.createControl(WebServiceMessageExtractor.class);
WebServiceMessageExtractor extractorMock = (WebServiceMessageExtractor) extractorControl.getMock();
extractorControl.replay();
MockControl faultResolverControl = MockControl.createControl(FaultResolver.class);
FaultResolver faultResolverMock = (FaultResolver) faultResolverControl.getMock();
template.setFaultResolver(faultResolverMock);
faultResolverMock.resolveFault(null);
MockControl faultResolverControl = MockControl.createControl(FaultMessageResolver.class);
FaultMessageResolver faultMessageResolverMock = (FaultMessageResolver) faultResolverControl.getMock();
template.setFaultMessageResolver(faultMessageResolverMock);
faultMessageResolverMock.resolveFault(null);
faultResolverControl.setMatcher(MockControl.ALWAYS_MATCHER);
faultResolverControl.replay();
connectionMock.send(null);
connectionControl.setMatcher(MockControl.ALWAYS_MATCHER);
connectionControl.expectAndReturn(connectionMock.hasError(), false);
connectionControl
.expectAndReturn(connectionMock.receive(messageFactory), new MockWebServiceMessage("<response/>"));
connectionControl.expectAndReturn(connectionMock.hasFault(), true);
connectionMock.close();
connectionControl.replay();
Object result = template.sendAndReceive(requestCallback, extractorMock);
Object result = template.sendAndReceive(null, extractorMock);
assertNull("Invalid response", result);
callbackControl.verify();
extractorControl.verify();
connectionControl.verify();
faultResolverControl.verify();
}
public void testSendAndReceiveConnectionError() throws Exception {
MockControl extractorControl = MockControl.createControl(WebServiceMessageExtractor.class);
WebServiceMessageExtractor extractorMock = (WebServiceMessageExtractor) extractorControl.getMock();
extractorControl.replay();
template.setFaultMessageResolver(null);
connectionMock.send(null);
connectionControl.setMatcher(MockControl.ALWAYS_MATCHER);
connectionControl.expectAndReturn(connectionMock.hasError(), true);
String errorMessage = "errorMessage";
connectionControl.expectAndReturn(connectionMock.getErrorMessage(), errorMessage, 2);
connectionMock.close();
connectionControl.replay();
try {
template.sendAndReceive(null, extractorMock);
fail("Expected WebServiceTransportException");
}
catch (WebServiceTransportException ex) {
//expected
assertEquals("Invalid exception message", errorMessage, ex.getMessage());
}
extractorControl.verify();
connectionControl.verify();
}
@@ -187,6 +206,7 @@ public class WebServiceTemplateTest extends XMLTestCase {
connectionMock.send(null);
connectionControl.setMatcher(MockControl.ALWAYS_MATCHER);
connectionControl.expectAndReturn(connectionMock.hasError(), false);
connectionControl
.expectAndReturn(connectionMock.receive(messageFactory), new MockWebServiceMessage("<response/>"));
connectionControl.expectAndReturn(connectionMock.hasFault(), false);
@@ -207,6 +227,7 @@ public class WebServiceTemplateTest extends XMLTestCase {
connectionMock.send(null);
connectionControl.setMatcher(MockControl.ALWAYS_MATCHER);
connectionControl.expectAndReturn(connectionMock.hasError(), false);
connectionControl.expectAndReturn(connectionMock.receive(messageFactory), null);
connectionMock.close();
connectionControl.replay();
@@ -221,6 +242,7 @@ public class WebServiceTemplateTest extends XMLTestCase {
public void testSendAndReceiveResultResponse() throws Exception {
connectionMock.send(null);
connectionControl.setMatcher(MockControl.ALWAYS_MATCHER);
connectionControl.expectAndReturn(connectionMock.hasError(), false);
connectionControl
.expectAndReturn(connectionMock.receive(messageFactory), new MockWebServiceMessage("<response/>"));
connectionControl.expectAndReturn(connectionMock.hasFault(), false);
@@ -228,7 +250,24 @@ public class WebServiceTemplateTest extends XMLTestCase {
connectionControl.replay();
StringResult result = new StringResult();
template.sendAndReceive(new StringSource("<request />"), result);
boolean b = template.sendAndReceive(new StringSource("<request />"), result);
assertTrue("Invalid result", b);
connectionControl.verify();
}
public void testSendAndReceiveResultNoResponse() throws Exception {
connectionMock.send(null);
connectionControl.setMatcher(MockControl.ALWAYS_MATCHER);
connectionControl.expectAndReturn(connectionMock.hasError(), false);
connectionControl
.expectAndReturn(connectionMock.receive(messageFactory), null);
connectionMock.close();
connectionControl.replay();
StringResult result = new StringResult();
boolean b = template.sendAndReceive(new StringSource("<request />"), result);
assertFalse("Invalid result", b);
connectionControl.verify();
}
@@ -252,6 +291,7 @@ public class WebServiceTemplateTest extends XMLTestCase {
connectionMock.send(null);
connectionControl.setMatcher(MockControl.ALWAYS_MATCHER);
connectionControl.expectAndReturn(connectionMock.hasError(), false);
connectionControl
.expectAndReturn(connectionMock.receive(messageFactory), new MockWebServiceMessage("<response/>"));
connectionControl.expectAndReturn(connectionMock.hasFault(), false);
@@ -281,6 +321,7 @@ public class WebServiceTemplateTest extends XMLTestCase {
connectionMock.send(null);
connectionControl.setMatcher(MockControl.ALWAYS_MATCHER);
connectionControl.expectAndReturn(connectionMock.hasError(), false);
connectionControl
.expectAndReturn(connectionMock.receive(messageFactory), null);
connectionMock.close();
@@ -309,7 +350,7 @@ public class WebServiceTemplateTest extends XMLTestCase {
});
MockControl callbackControl = MockControl.createControl(WebServiceMessageCallback.class);
WebServiceMessageCallback requestCallback = (WebServiceMessageCallback) callbackControl.getMock();
requestCallback.doInMessage(null);
requestCallback.doWithMessage(null);
callbackControl.setMatcher(MockControl.ALWAYS_MATCHER);
callbackControl.replay();
@@ -323,6 +364,7 @@ public class WebServiceTemplateTest extends XMLTestCase {
connectionMock.send(null);
connectionControl.setMatcher(MockControl.ALWAYS_MATCHER);
connectionControl.expectAndReturn(connectionMock.hasError(), false);
connectionControl
.expectAndReturn(connectionMock.receive(messageFactory), new MockWebServiceMessage("<response/>"));
connectionControl.expectAndReturn(connectionMock.hasFault(), false);

View File

@@ -22,8 +22,6 @@ import org.springframework.ws.WebServiceMessageFactory;
public class DomPoxMessageFactoryTest extends AbstractWebServiceMessageFactoryTestCase {
protected WebServiceMessageFactory createMessageFactory() throws Exception {
DomPoxMessageFactory factory = new DomPoxMessageFactory();
factory.afterPropertiesSet();
return factory;
return new DomPoxMessageFactory();
}
}

View File

@@ -41,7 +41,7 @@ public class DomPoxMessageTest extends XMLTestCase {
Document document = documentBuilder.newDocument();
TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformer = transformerFactory.newTransformer();
message = new DomPoxMessage(document, transformer);
message = new DomPoxMessage(document, transformer, DomPoxMessageFactory.DEFAULT_CONTENT_TYPE);
}
public void testGetPayload() throws Exception {

View File

@@ -1,3 +1,4 @@
<?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">
<modelVersion>4.0.0</modelVersion>
@@ -280,7 +281,6 @@
<configuration>
<aggregate>true</aggregate>
<breakiterator>true</breakiterator>
<stylesheetfile>${basedir}/src/site/resources/css/javadoc.css</stylesheetfile>
<groups>
<group>
<title>Spring-WS</title>
@@ -566,7 +566,7 @@
<dependency>
<groupId>com.sun.xml.wss</groupId>
<artifactId>xws-security</artifactId>
<version>2.0-fcs</version>
<version>2.0-FCS</version>
</dependency>
<dependency>
<groupId>com.sun.org.apache.xml.security</groupId>
@@ -690,4 +690,4 @@
<scope>test</scope>
</dependency>
</dependencies>
</project>
</project>

View File

@@ -6,6 +6,12 @@
</properties>
<body>
<release version="1.0-rc2">
<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()
</action>
<action dev="poutsma" type="update">Renamed FaultResolver to FaultMessageResolver</action>
<action dev="poutsma" type="update">Moved SoapActionCallback to soap package</action>
<action dev="poutsma" type="fix">Added an MTOM sample</action>
<action dev="poutsma" type="fix">Fixed various MTOM issues</action>
<action dev="poutsma" type="add" issue="SWS-135">Implement client-side TransportContext</action>

View File

@@ -2,6 +2,23 @@
Upgrading
---------
Upgrading from version 1.0-RC1 to 1.0-RC2
Some minor last changes were made between version 1.0 Release Candidate 1 and 2of the project. The following
should help most users the project update their applications:
* Client-side
Some issues have been resolved which make the WebServiceTemplate more useable in Plain Old XML settings, and less
SOAP-specific.
* The <<<WebServiceMessageCallback>>> method <<<doInMessage()>>> has been renamed to <<<doWithMessage()>>>, since it
was poorly named.
* The <<<FaultResolver>>> has been renamed to <<<FaultMessageReceiver>>> to indicate its responsibility more clearly.
* The <<<SoapActionCallback>>> has been moved to <<<org.springframework.ws.soap.client.core>>>.
Upgrading from version 1.0-M3 to 1.0-RC1
Some minor changes were made between version 1.0 Milestone 3 and Release Candidate 1 of the project. The following