From 2f75e420a57bebef5777535489c1a528fe7782da Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Thu, 7 Jun 2007 00:35:37 +0000 Subject: [PATCH] - 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. --- .../ws/client/WebServiceFaultException.java | 21 +- ...esolver.java => FaultMessageResolver.java} | 4 +- ...r.java => SimpleFaultMessageResolver.java} | 9 +- .../core/WebServiceMessageCallback.java | 10 +- .../ws/client/core/WebServiceOperations.java | 28 +- .../ws/client/core/WebServiceTemplate.java | 289 ++++++++++-------- .../support/WebServiceGatewaySupport.java | 9 +- .../ws/client/support/WebServiceAccessor.java | 4 +- .../ws/pox/dom/DomPoxMessage.java | 30 +- .../ws/pox/dom/DomPoxMessageFactory.java | 55 ++-- .../ws/server/MessageDispatcher.java | 39 ++- .../mapping/AbstractEndpointMapping.java | 1 - .../springframework/ws/soap/SoapFault.java | 14 +- .../soap/client/SoapFaultClientException.java | 67 ++++ .../client/core}/SoapActionCallback.java | 8 +- .../client/core/SoapFaultMessageResolver.java | 38 +++ .../ws/soap/client/core/package.html | 5 + .../ws/soap/client/package.html | 5 + .../ws/soap/saaj/SaajSoapMessageFactory.java | 4 +- .../FaultAwareWebServiceConnection.java | 7 +- .../ws/transport/WebServiceConnection.java | 16 + .../http/AbstractHttpSenderConnection.java | 9 +- .../transport/http/CommonsHttpConnection.java | 10 +- .../transport/http/HttpServletConnection.java | 26 +- .../ws/transport/http/HttpUrlConnection.java | 12 +- .../http/MessageDispatcherServlet.java | 106 +++---- .../support/DefaultStrategiesHelper.java | 101 +++++- ...ebServiceMessageReceiverObjectSupport.java | 1 - .../client/core/WebServiceTemplate.properties | 2 +- ...va => SimpleFaultMessageResolverTest.java} | 6 +- .../ws/client/core/SimpleSaajServlet.java | 32 +- .../WebServiceTemplateIntegrationTest.java | 233 +++++++++++++- .../client/core/WebServiceTemplateTest.java | 88 ++++-- .../ws/pox/dom/DomPoxMessageFactoryTest.java | 4 +- .../ws/pox/dom/DomPoxMessageTest.java | 2 +- pom.xml | 6 +- src/changes/changes.xml | 6 + src/site/apt/upgrading.apt | 17 ++ 38 files changed, 920 insertions(+), 404 deletions(-) rename core/src/main/java/org/springframework/ws/client/core/{FaultResolver.java => FaultMessageResolver.java} (86%) rename core/src/main/java/org/springframework/ws/client/core/{SimpleFaultResolver.java => SimpleFaultMessageResolver.java} (74%) create mode 100644 core/src/main/java/org/springframework/ws/soap/client/SoapFaultClientException.java rename core/src/main/java/org/springframework/ws/{client/core/support => soap/client/core}/SoapActionCallback.java (87%) create mode 100644 core/src/main/java/org/springframework/ws/soap/client/core/SoapFaultMessageResolver.java create mode 100644 core/src/main/java/org/springframework/ws/soap/client/core/package.html create mode 100644 core/src/main/java/org/springframework/ws/soap/client/package.html rename core/src/test/java/org/springframework/ws/client/core/{SimpleFaultResolverTest.java => SimpleFaultMessageResolverTest.java} (90%) diff --git a/core/src/main/java/org/springframework/ws/client/WebServiceFaultException.java b/core/src/main/java/org/springframework/ws/client/WebServiceFaultException.java index 57e25e18..0042b3cb 100644 --- a/core/src/main/java/org/springframework/ws/client/WebServiceFaultException.java +++ b/core/src/main/java/org/springframework/ws/client/WebServiceFaultException.java @@ -16,18 +16,29 @@ package org.springframework.ws.client; +import org.springframework.ws.WebServiceMessage; + /** - * Thrown by SimpleFaultResolver when the response message has a fault. + * Thrown by SimpleFaultMessageResolver 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 WebServiceFaultException 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; } } diff --git a/core/src/main/java/org/springframework/ws/client/core/FaultResolver.java b/core/src/main/java/org/springframework/ws/client/core/FaultMessageResolver.java similarity index 86% rename from core/src/main/java/org/springframework/ws/client/core/FaultResolver.java rename to core/src/main/java/org/springframework/ws/client/core/FaultMessageResolver.java index bcb8a6e8..97ca4ec9 100644 --- a/core/src/main/java/org/springframework/ws/client/core/FaultResolver.java +++ b/core/src/main/java/org/springframework/ws/client/core/FaultMessageResolver.java @@ -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. diff --git a/core/src/main/java/org/springframework/ws/client/core/SimpleFaultResolver.java b/core/src/main/java/org/springframework/ws/client/core/SimpleFaultMessageResolver.java similarity index 74% rename from core/src/main/java/org/springframework/ws/client/core/SimpleFaultResolver.java rename to core/src/main/java/org/springframework/ws/client/core/SimpleFaultMessageResolver.java index 40cd8dcf..7102d9e5 100644 --- a/core/src/main/java/org/springframework/ws/client/core/SimpleFaultResolver.java +++ b/core/src/main/java/org/springframework/ws/client/core/SimpleFaultMessageResolver.java @@ -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 WebServiceFaultException. */ public void resolveFault(WebServiceMessage message) { - throw new WebServiceFaultException(message.getFaultReason()); + throw new WebServiceFaultException(message); } } diff --git a/core/src/main/java/org/springframework/ws/client/core/WebServiceMessageCallback.java b/core/src/main/java/org/springframework/ws/client/core/WebServiceMessageCallback.java index 7e360e2b..dbf06ec3 100644 --- a/core/src/main/java/org/springframework/ws/client/core/WebServiceMessageCallback.java +++ b/core/src/main/java/org/springframework/ws/client/core/WebServiceMessageCallback.java @@ -22,20 +22,20 @@ import org.springframework.ws.WebServiceMessage; /** * Generic callback interface for code that operates on a {@link WebServiceMessage}. - * - *

Implementations can execute any number of operations on the message, such as - * set the contents of the message, or set the SOAPAction header. + *

+ * Implementations can execute any number of operations on the message, such as set the contents of the message, or set + * the SOAPAction header. * * @author Arjen Poutsma */ public interface WebServiceMessageCallback { /** - * Execute any number of operations on the supplied message. + * Execute any number of operations on the supplied message. * * @param message the message * @throws IOException in case of I/O errors */ - void doInMessage(WebServiceMessage message) throws IOException; + void doWithMessage(WebServiceMessage message) throws IOException; } diff --git a/core/src/main/java/org/springframework/ws/client/core/WebServiceOperations.java b/core/src/main/java/org/springframework/ws/client/core/WebServiceOperations.java index fe4a2910..ae844b21 100644 --- a/core/src/main/java/org/springframework/ws/client/core/WebServiceOperations.java +++ b/core/src/main/java/org/springframework/ws/client/core/WebServiceOperations.java @@ -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 true if a response was received; false 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 true if a response was received; false 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 null * @param responseResult the result to write the response payload to + * @return true if a response was received; false 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 null * @param responseResult the result to write the response payload to + * @return true if a response was received; false 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 true if a response was received; false 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 true if a response was received; false 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; } diff --git a/core/src/main/java/org/springframework/ws/client/core/WebServiceTemplate.java b/core/src/main/java/org/springframework/ws/client/core/WebServiceTemplate.java index 9af253b4..dc497333 100644 --- a/core/src/main/java/org/springframework/ws/client/core/WebServiceTemplate.java +++ b/core/src/main/java/org/springframework/ws/client/core/WebServiceTemplate.java @@ -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; /** * The central class for client-side Web services. It provides a message-driven approach to sending and - * receiving {@link org.springframework.ws.WebServiceMessage} instances. + * receiving {@link WebServiceMessage} instances. *

* Code using this class need only implement callback interfaces, provide {@link Source} objects to read data from, or * use the pluggable {@link Marshaller} support. *

- * 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 null, 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 WebServiceTemplate 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 + * null 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 true if either the connection or the message has a fault; false 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; } } diff --git a/core/src/main/java/org/springframework/ws/client/core/support/WebServiceGatewaySupport.java b/core/src/main/java/org/springframework/ws/client/core/support/WebServiceGatewaySupport.java index 6a850b6a..22d348c5 100644 --- a/core/src/main/java/org/springframework/ws/client/core/support/WebServiceGatewaySupport.java +++ b/core/src/main/java/org/springframework/ws/client/core/support/WebServiceGatewaySupport.java @@ -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(); diff --git a/core/src/main/java/org/springframework/ws/client/support/WebServiceAccessor.java b/core/src/main/java/org/springframework/ws/client/support/WebServiceAccessor.java index 816d63bb..3b8faf4c 100644 --- a/core/src/main/java/org/springframework/ws/client/support/WebServiceAccessor.java +++ b/core/src/main/java/org/springframework/ws/client/support/WebServiceAccessor.java @@ -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"); } diff --git a/core/src/main/java/org/springframework/ws/pox/dom/DomPoxMessage.java b/core/src/main/java/org/springframework/ws/pox/dom/DomPoxMessage.java index 5cefbff0..5b94b92d 100644 --- a/core/src/main/java/org/springframework/ws/pox/dom/DomPoxMessage.java +++ b/core/src/main/java/org/springframework/ws/pox/dom/DomPoxMessage.java @@ -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 PoxMessage 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 DomPoxMessage 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)); } diff --git a/core/src/main/java/org/springframework/ws/pox/dom/DomPoxMessageFactory.java b/core/src/main/java/org/springframework/ws/pox/dom/DomPoxMessageFactory.java index b12d5aee..ac303687 100644 --- a/core/src/main/java/org/springframework/ws/pox/dom/DomPoxMessageFactory.java +++ b/core/src/main/java/org/springframework/ws/pox/dom/DomPoxMessageFactory.java @@ -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 true. - */ + /** 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 true. */ public void setNamespaceAware(boolean namespaceAware) { - this.namespaceAware = namespaceAware; - } - - /** - * Set if the XML parser should validate the document. Default is false. - */ - 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 false. */ + 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); diff --git a/core/src/main/java/org/springframework/ws/server/MessageDispatcher.java b/core/src/main/java/org/springframework/ws/server/MessageDispatcher.java index e12f8e44..8c2f8219 100644 --- a/core/src/main/java/org/springframework/ws/server/MessageDispatcher.java +++ b/core/src/main/java/org/springframework/ws/server/MessageDispatcher.java @@ -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. *

- * 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. - *

+ * 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. * * @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"); } } } diff --git a/core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractEndpointMapping.java b/core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractEndpointMapping.java index 05298a18..1b48ba5e 100644 --- a/core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractEndpointMapping.java +++ b/core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractEndpointMapping.java @@ -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 + "]"); } /** diff --git a/core/src/main/java/org/springframework/ws/soap/SoapFault.java b/core/src/main/java/org/springframework/ws/soap/SoapFault.java index 4f24e297..930dc2ac 100644 --- a/core/src/main/java/org/springframework/ws/soap/SoapFault.java +++ b/core/src/main/java/org/springframework/ws/soap/SoapFault.java @@ -26,11 +26,7 @@ import javax.xml.namespace.QName; */ public interface SoapFault extends SoapElement { - /** - * Returns the fault code. - * - * @return a QName 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); /** diff --git a/core/src/main/java/org/springframework/ws/soap/client/SoapFaultClientException.java b/core/src/main/java/org/springframework/ws/soap/client/SoapFaultClientException.java new file mode 100644 index 00000000..a2ce72e7 --- /dev/null +++ b/core/src/main/java/org/springframework/ws/soap/client/SoapFaultClientException.java @@ -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 SoapFaultMessageResolver 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 SoapFaultClientException 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. + *

+ * Note that this message returns the same as {@link #getMessage()}. + */ + public String getFaultStringOrReason() { + return soapFault != null ? soapFault.getFaultStringOrReason() : null; + } + + +} diff --git a/core/src/main/java/org/springframework/ws/client/core/support/SoapActionCallback.java b/core/src/main/java/org/springframework/ws/soap/client/core/SoapActionCallback.java similarity index 87% rename from core/src/main/java/org/springframework/ws/client/core/support/SoapActionCallback.java rename to core/src/main/java/org/springframework/ws/soap/client/core/SoapActionCallback.java index dc7d9e69..66a01077 100644 --- a/core/src/main/java/org/springframework/ws/client/core/support/SoapActionCallback.java +++ b/core/src/main/java/org/springframework/ws/soap/client/core/SoapActionCallback.java @@ -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 SoapActionCallback with the given string SOAPAction. - */ + /** Create a new SoapActionCallback 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); } diff --git a/core/src/main/java/org/springframework/ws/soap/client/core/SoapFaultMessageResolver.java b/core/src/main/java/org/springframework/ws/soap/client/core/SoapFaultMessageResolver.java new file mode 100644 index 00000000..4335689a --- /dev/null +++ b/core/src/main/java/org/springframework/ws/soap/client/core/SoapFaultMessageResolver.java @@ -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); + } +} diff --git a/core/src/main/java/org/springframework/ws/soap/client/core/package.html b/core/src/main/java/org/springframework/ws/soap/client/core/package.html new file mode 100644 index 00000000..5cee2505 --- /dev/null +++ b/core/src/main/java/org/springframework/ws/soap/client/core/package.html @@ -0,0 +1,5 @@ + + +Contains core classes for SOAP-specific client-side Spring-WS support. + + diff --git a/core/src/main/java/org/springframework/ws/soap/client/package.html b/core/src/main/java/org/springframework/ws/soap/client/package.html new file mode 100644 index 00000000..8525972d --- /dev/null +++ b/core/src/main/java/org/springframework/ws/soap/client/package.html @@ -0,0 +1,5 @@ + + +Contains classes for SOAP-specific client-side Spring-WS support. + + diff --git a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java index 9f6bdea0..e0d083f4 100644 --- a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java +++ b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java @@ -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() + "]"); } } diff --git a/core/src/main/java/org/springframework/ws/transport/FaultAwareWebServiceConnection.java b/core/src/main/java/org/springframework/ws/transport/FaultAwareWebServiceConnection.java index d9f81edd..d4122a9d 100644 --- a/core/src/main/java/org/springframework/ws/transport/FaultAwareWebServiceConnection.java +++ b/core/src/main/java/org/springframework/ws/transport/FaultAwareWebServiceConnection.java @@ -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 true if this connection has a fault; false otherwise. */ diff --git a/core/src/main/java/org/springframework/ws/transport/WebServiceConnection.java b/core/src/main/java/org/springframework/ws/transport/WebServiceConnection.java index 7ac0d1ba..db7068a3 100644 --- a/core/src/main/java/org/springframework/ws/transport/WebServiceConnection.java +++ b/core/src/main/java/org/springframework/ws/transport/WebServiceConnection.java @@ -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 true if this connection has an error; false otherwise. + */ + boolean hasError() throws IOException; + + /** + * Returns the error message. + * + * @return the connection error message, if any; returns null when no error is present + * @see #hasError() + */ + String getErrorMessage() throws IOException; + /** * Closes this connection. *

diff --git a/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpSenderConnection.java b/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpSenderConnection.java index c5a4984d..cd4c87ca 100644 --- a/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpSenderConnection.java +++ b/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpSenderConnection.java @@ -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 { diff --git a/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpConnection.java b/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpConnection.java index a2fe6687..fe91ca35 100644 --- a/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpConnection.java +++ b/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpConnection.java @@ -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(); } diff --git a/core/src/main/java/org/springframework/ws/transport/http/HttpServletConnection.java b/core/src/main/java/org/springframework/ws/transport/http/HttpServletConnection.java index 1f0dfeeb..8ace983f 100644 --- a/core/src/main/java/org/springframework/ws/transport/http/HttpServletConnection.java +++ b/core/src/main/java/org/springframework/ws/transport/http/HttpServletConnection.java @@ -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); } } } diff --git a/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnection.java b/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnection.java index 02d3bd77..439d262a 100644 --- a/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnection.java +++ b/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnection.java @@ -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(); } } } diff --git a/core/src/main/java/org/springframework/ws/transport/http/MessageDispatcherServlet.java b/core/src/main/java/org/springframework/ws/transport/http/MessageDispatcherServlet.java index 7e31f0e5..274ea478 100644 --- a/core/src/main/java/org/springframework/ws/transport/http/MessageDispatcherServlet.java +++ b/core/src/main/java/org/springframework/ws/transport/http/MessageDispatcherServlet.java @@ -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. - * - *

This servlet is a convenient alternative to the standard Spring-MVC - * {@link DispatcherServlet} with separate - * {@link WebServiceMessageReceiverHandlerAdapter}, {@link MessageDispatcher}, and - * {@link WsdlDefinitionHandlerAdapter} instances. - * - *

This servlet automatically detects {@link EndpointAdapter EndpointAdapters}, - * {@link EndpointMapping EndpointMappings}, and - * {@link EndpointExceptionResolver EndpointExceptionResolvers} by type. - * - *

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 'echo' will be exposed as - * echo.wsdl in this servlet's context: - * http://localhost:8080/spring-ws/echo.wsdl. When the - * transformWsdlLocations init-param is set to true in - * this servlet's configuration in web.xml, all location - * attributes in the WSDL definitions will reflect the URL of the incoming request. + *

+ *

This servlet is a convenient alternative to the standard Spring-MVC {@link DispatcherServlet} with separate {@link + * WebServiceMessageReceiverHandlerAdapter}, {@link MessageDispatcher}, and {@link WsdlDefinitionHandlerAdapter} + * instances. + *

+ *

This servlet automatically detects {@link EndpointAdapter EndpointAdapters}, {@link EndpointMapping + * EndpointMappings}, and {@link EndpointExceptionResolver EndpointExceptionResolvers} by type. + *

+ *

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 'echo' will be exposed as + * echo.wsdl in this servlet's context: http://localhost:8080/spring-ws/echo.wsdl. When the + * transformWsdlLocations init-param is set to true in this servlet's configuration in + * web.xml, all location 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 MessageDispatcherServlet's default strategy names. + * Name of the class path resource (relative to the {@link MessageDispatcherServlet} class) that defines + * MessageDispatcherServlet's 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}. - *

Defaults to false. + * Sets whether relative address locations in the WSDL are to be transformed using the request URI of the incoming + * {@link HttpServletRequest}.

Defaults to false. */ 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 null - * if none is found. + * Determines the {@link WsdlDefinition} for a given request, or null if none is found. *

- * Default implementation checks whether the request method is GET, - * whether the request uri ends with ".wsdl", and if there is a - * WsdlDefinition with the same name as the filename in the request uri. + * Default implementation checks whether the request method is GET, whether the request uri ends with + * ".wsdl", and if there is a WsdlDefinition with the same name as the filename in the + * request uri. + * * @param request the HttpServletRequest * @return a definition, or null */ 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); } } diff --git a/core/src/main/java/org/springframework/ws/transport/support/DefaultStrategiesHelper.java b/core/src/main/java/org/springframework/ws/transport/support/DefaultStrategiesHelper.java index 6686ee3e..a1543aa1 100644 --- a/core/src/main/java/org/springframework/ws/transport/support/DefaultStrategiesHelper.java +++ b/core/src/main/java/org/springframework/ws/transport/support/DefaultStrategiesHelper.java @@ -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. + *

+ * 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 - * Properties object. It instantiates the strategy objects and satisifies + * Create a list of strategy objects for the given strategy interface. Strategies are retrieved from the + * Properties 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 + * Properties object given at construction-time. It instantiates the strategy objects and satisifies * ApplicationContextAware 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 + * null * @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.

Delegates to - * getDefaultStrategies, 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. + *

+ * 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 + * null + * @return the corresponding strategy object + * @throws BeansException if initialization failed + */ public Object getDefaultStrategy(Class strategyInterface, ApplicationContext applicationContext) throws BeanInitializationException { List result = getDefaultStrategies(strategyInterface, applicationContext); diff --git a/core/src/main/java/org/springframework/ws/transport/support/WebServiceMessageReceiverObjectSupport.java b/core/src/main/java/org/springframework/ws/transport/support/WebServiceMessageReceiverObjectSupport.java index fa5f040c..63c3a7a7 100644 --- a/core/src/main/java/org/springframework/ws/transport/support/WebServiceMessageReceiverObjectSupport.java +++ b/core/src/main/java/org/springframework/ws/transport/support/WebServiceMessageReceiverObjectSupport.java @@ -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 + "]"); } /** diff --git a/core/src/main/resources/org/springframework/ws/client/core/WebServiceTemplate.properties b/core/src/main/resources/org/springframework/ws/client/core/WebServiceTemplate.properties index 539831b6..2078d301 100644 --- a/core/src/main/resources/org/springframework/ws/client/core/WebServiceTemplate.properties +++ b/core/src/main/resources/org/springframework/ws/client/core/WebServiceTemplate.properties @@ -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 \ No newline at end of file diff --git a/core/src/test/java/org/springframework/ws/client/core/SimpleFaultResolverTest.java b/core/src/test/java/org/springframework/ws/client/core/SimpleFaultMessageResolverTest.java similarity index 90% rename from core/src/test/java/org/springframework/ws/client/core/SimpleFaultResolverTest.java rename to core/src/test/java/org/springframework/ws/client/core/SimpleFaultMessageResolverTest.java index 72fb4c31..822a0fd3 100644 --- a/core/src/test/java/org/springframework/ws/client/core/SimpleFaultResolverTest.java +++ b/core/src/test/java/org/springframework/ws/client/core/SimpleFaultMessageResolverTest.java @@ -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 { diff --git a/core/src/test/java/org/springframework/ws/client/core/SimpleSaajServlet.java b/core/src/test/java/org/springframework/ws/client/core/SimpleSaajServlet.java index 13bd7f77..103af9e4 100644 --- a/core/src/test/java/org/springframework/ws/client/core/SimpleSaajServlet.java +++ b/core/src/test/java/org/springframework/ws/client/core/SimpleSaajServlet.java @@ -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; } diff --git a/core/src/test/java/org/springframework/ws/client/core/WebServiceTemplateIntegrationTest.java b/core/src/test/java/org/springframework/ws/client/core/WebServiceTemplateIntegrationTest.java index 09d16df4..b6ad6519 100644 --- a/core/src/test/java/org/springframework/ws/client/core/WebServiceTemplateIntegrationTest.java +++ b/core/src/test/java/org/springframework/ws/client/core/WebServiceTemplateIntegrationTest.java @@ -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 = ""; - 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 = ""; 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 = ""; + 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; + } + } } diff --git a/core/src/test/java/org/springframework/ws/client/core/WebServiceTemplateTest.java b/core/src/test/java/org/springframework/ws/client/core/WebServiceTemplateTest.java index 9523c743..8a937420 100644 --- a/core/src/test/java/org/springframework/ws/client/core/WebServiceTemplateTest.java +++ b/core/src/test/java/org/springframework/ws/client/core/WebServiceTemplateTest.java @@ -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("")); 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("")); 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("")); 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("")); connectionControl.expectAndReturn(connectionMock.hasFault(), false); @@ -228,7 +250,24 @@ public class WebServiceTemplateTest extends XMLTestCase { connectionControl.replay(); StringResult result = new StringResult(); - template.sendAndReceive(new StringSource(""), result); + boolean b = template.sendAndReceive(new StringSource(""), 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(""), 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("")); 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("")); connectionControl.expectAndReturn(connectionMock.hasFault(), false); diff --git a/core/src/test/java/org/springframework/ws/pox/dom/DomPoxMessageFactoryTest.java b/core/src/test/java/org/springframework/ws/pox/dom/DomPoxMessageFactoryTest.java index f36c102f..162b6716 100644 --- a/core/src/test/java/org/springframework/ws/pox/dom/DomPoxMessageFactoryTest.java +++ b/core/src/test/java/org/springframework/ws/pox/dom/DomPoxMessageFactoryTest.java @@ -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(); } } \ No newline at end of file diff --git a/core/src/test/java/org/springframework/ws/pox/dom/DomPoxMessageTest.java b/core/src/test/java/org/springframework/ws/pox/dom/DomPoxMessageTest.java index 94038d4c..7ba87ed5 100644 --- a/core/src/test/java/org/springframework/ws/pox/dom/DomPoxMessageTest.java +++ b/core/src/test/java/org/springframework/ws/pox/dom/DomPoxMessageTest.java @@ -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 { diff --git a/pom.xml b/pom.xml index 7775aa97..b7ecf92d 100644 --- a/pom.xml +++ b/pom.xml @@ -1,3 +1,4 @@ + 4.0.0 @@ -280,7 +281,6 @@ true true - ${basedir}/src/site/resources/css/javadoc.css Spring-WS @@ -566,7 +566,7 @@ com.sun.xml.wss xws-security - 2.0-fcs + 2.0-FCS com.sun.org.apache.xml.security @@ -690,4 +690,4 @@ test - \ No newline at end of file + diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 335093b6..be0453ee 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -6,6 +6,12 @@ + WebServiceTemplate returns boolean values rather than void + Changed WebServiceMessageCallback's doInMessage() to + doWithMessage() + + Renamed FaultResolver to FaultMessageResolver + Moved SoapActionCallback to soap package Added an MTOM sample Fixed various MTOM issues Implement client-side TransportContext diff --git a/src/site/apt/upgrading.apt b/src/site/apt/upgrading.apt index 72770877..b4d3cc2c 100644 --- a/src/site/apt/upgrading.apt +++ b/src/site/apt/upgrading.apt @@ -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 <<>> method <<>> has been renamed to <<>>, since it + was poorly named. + + * The <<>> has been renamed to <<>> to indicate its responsibility more clearly. + + * The <<>> has been moved to <<>>. + 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