From 07625024e12afc0e3b9e6db889aad822a07295cc Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Sun, 20 May 2007 10:10:31 +0000 Subject: [PATCH] Implemented #SWS-98: Changing URL in CommonsHttpMessageSender --- .../ws/client/core/WebServiceOperations.java | 134 ++++++++++ .../ws/client/core/WebServiceTemplate.java | 212 ++++++++++------ .../support/WebServiceGatewaySupport.java | 35 ++- .../ws/client/support/WebServiceAccessor.java | 69 +++--- .../ws/client/support/package.html | 6 + ...n.java => AbstractReceiverConnection.java} | 19 +- ...ion.java => AbstractSenderConnection.java} | 20 +- .../AbstractWebServiceConnection.java | 102 ++++++++ .../EndpointAwareWebServiceConnection.java | 33 +++ .../ws/transport/WebServiceConnection.java | 42 +--- .../ws/transport/WebServiceMessageSender.java | 19 +- ...java => AbstractHttpSenderConnection.java} | 4 +- .../AbstractHttpWebServiceMessageSender.java | 24 +- .../transport/http/CommonsHttpConnection.java | 9 +- .../http/CommonsHttpMessageSender.java | 4 +- .../transport/http/HttpServletConnection.java | 58 +++-- .../ws/transport/http/HttpUrlConnection.java | 10 +- .../http/HttpUrlConnectionMessageSender.java | 12 +- ...bServiceMessageReceiverHandlerAdapter.java | 27 -- ...ebServiceMessageReceiverObjectSupport.java | 66 +---- .../ws/transport/support/package.html | 5 + .../client/core/WebServiceTemplate.properties | 3 +- .../ws/client/core/SimpleSaajServlet.java | 7 +- .../WebServiceTemplateIntegrationTest.java | 6 +- .../client/core/WebServiceTemplateTest.java | 123 ++++++--- .../support/WebServiceAccessorTest.java | 58 ----- ...rviceMessageSenderIntegrationTestCase.java | 234 +++++++++++------- .../http/HttpServletConnectionTest.java | 105 ++++---- ...viceMessageReceiverHandlerAdapterTest.java | 15 +- .../echo/client/sws/applicationContext.xml | 13 +- src/changes/changes.xml | 1 + src/site/apt/upgrading.apt | 20 +- 32 files changed, 913 insertions(+), 582 deletions(-) create mode 100644 core/src/main/java/org/springframework/ws/client/support/package.html rename core/src/main/java/org/springframework/ws/transport/{AbstractReceivingWebServiceConnection.java => AbstractReceiverConnection.java} (81%) rename core/src/main/java/org/springframework/ws/transport/{AbstractSendingWebServiceConnection.java => AbstractSenderConnection.java} (83%) create mode 100644 core/src/main/java/org/springframework/ws/transport/AbstractWebServiceConnection.java create mode 100644 core/src/main/java/org/springframework/ws/transport/EndpointAwareWebServiceConnection.java rename core/src/main/java/org/springframework/ws/transport/http/{AbstractHttpSendingWebServiceConnection.java => AbstractHttpSenderConnection.java} (94%) create mode 100644 core/src/main/java/org/springframework/ws/transport/support/package.html delete mode 100644 core/src/test/java/org/springframework/ws/client/support/WebServiceAccessorTest.java 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 5e9ff128..fe4a2910 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 @@ -34,6 +34,8 @@ public interface WebServiceOperations { /** * Sends a web service message that contains the given payload, marshalled by the configured * Marshaller. Returns the unmarshalled payload of the response message, if any. + *

+ * This will only work with a default specified! * * @param requestPayload the object to marshal into the request message payload * @return the unmarshalled payload of the response message, or null if no response is given @@ -44,10 +46,27 @@ public interface WebServiceOperations { */ Object marshalSendAndReceive(Object requestPayload) throws XmlMappingException, WebServiceClientException; + /** + * Sends a web service message that contains the given payload, marshalled by the configured + * Marshaller. Returns the unmarshalled payload of the response message, if any. + * + * @param uri the URI to send the message to + * @param requestPayload the object to marshal into the request message payload + * @return the unmarshalled payload of the response message, or null if no response is given + * @throws XmlMappingException if there is a problem marshalling or unmarshalling + * @throws WebServiceClientException if there is a problem sending or receiving the message + * @see WebServiceTemplate#setMarshaller(org.springframework.oxm.Marshaller) + * @see WebServiceTemplate#setUnmarshaller(org.springframework.oxm.Unmarshaller) + */ + Object marshalSendAndReceive(String uri, Object requestPayload) + throws XmlMappingException, WebServiceClientException; + /** * Sends a web service message that contains the given payload, marshalled by the configured * Marshaller. Returns the unmarshalled payload of the response message, if any. The given callback * allows changing of the request message after the payload has been marshalled to it. + *

+ * This will only work with a default specified! * * @param requestPayload the object to marshal into the request message payload * @param requestCallback callback to change message, can be null @@ -60,9 +79,28 @@ public interface WebServiceOperations { Object marshalSendAndReceive(Object requestPayload, WebServiceMessageCallback requestCallback) throws XmlMappingException, WebServiceClientException; + /** + * Sends a web service message that contains the given payload, marshalled by the configured + * Marshaller. Returns the unmarshalled payload of the response message, if any. The given callback + * allows changing of the request message after the payload has been marshalled to it. + * + * @param uri the URI to send the message to + * @param requestPayload the object to marshal into the request message payload + * @param requestCallback callback to change message, can be null + * @return the unmarshalled payload of the response message, or null if no response is given + * @throws XmlMappingException if there is a problem marshalling or unmarshalling + * @throws WebServiceClientException if there is a problem sending or receiving the message + * @see WebServiceTemplate#setMarshaller(org.springframework.oxm.Marshaller) + * @see WebServiceTemplate#setUnmarshaller(org.springframework.oxm.Unmarshaller) + */ + Object marshalSendAndReceive(String uri, Object requestPayload, WebServiceMessageCallback requestCallback) + throws XmlMappingException, WebServiceClientException; + /** * Sends a web service message that contains the given payload, reading the result with a * SourceExtractor. + *

+ * This will only work with a default specified! * * @param requestPayload the payload of the request message * @param responseExtractor object that will extract results @@ -71,11 +109,26 @@ public interface WebServiceOperations { */ Object sendAndReceive(Source requestPayload, SourceExtractor responseExtractor) throws WebServiceClientException; + /** + * Sends a web service message that contains the given payload, reading the result with a + * SourceExtractor. + * + * @param uri the URI to send the message to + * @param requestPayload the payload of the request message + * @param responseExtractor object that will extract results + * @return an arbitrary result object, as returned by the SourceExtractor + * @throws WebServiceClientException if there is a problem sending or receiving the message + */ + Object sendAndReceive(String uri, Source requestPayload, SourceExtractor responseExtractor) + throws WebServiceClientException; + /** * Sends a web service message that contains the given payload, reading the result with a * SourceExtractor. *

* The given callback allows changing of the request message after the payload has been written to it. + *

+ * This will only work with a default specified! * * @param requestPayload the payload of the request message * @param requestCallback callback to change message, can be null @@ -87,9 +140,29 @@ public interface WebServiceOperations { WebServiceMessageCallback requestCallback, SourceExtractor responseExtractor) throws WebServiceClientException; + /** + * Sends a web service message that contains the given payload, reading the result with a + * SourceExtractor. + *

+ * The given callback allows changing of the request message after the payload has been written to it. + * + * @param uri the URI to send the message to + * @param requestPayload the payload of the request message + * @param requestCallback callback to change message, can be null + * @param responseExtractor object that will extract results + * @return an arbitrary result object, as returned by the SourceExtractor + * @throws WebServiceClientException if there is a problem sending or receiving the message + */ + Object sendAndReceive(String uri, + Source requestPayload, + WebServiceMessageCallback requestCallback, + SourceExtractor responseExtractor) throws WebServiceClientException; + /** * Sends a web service message that contains the given payload. Writes the response, if any, to the given * Result. + *

+ * This will only work with a default specified! * * @param requestPayload the payload of the request message * @param responseResult the result to write the response payload to @@ -97,11 +170,24 @@ public interface WebServiceOperations { */ void 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 + * Result. + * + * @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 + * @throws WebServiceClientException if there is a problem sending or receiving the message + */ + void 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 * Result. *

* The given callback allows changing of the request message after the payload has been written to it. + *

+ * This will only work with a default specified! * * @param requestPayload the payload of the request message * @param requestCallback callback to change message, can be null @@ -111,9 +197,28 @@ public interface WebServiceOperations { void sendAndReceive(Source requestPayload, WebServiceMessageCallback requestCallback, Result responseResult) throws WebServiceClientException; + /** + * Sends a web service message that contains the given payload. Writes the response, if any, to the given + * Result. + *

+ * The given callback allows changing of the request message after the payload has been written to it. + * + * @param uri the URI to send the message to + * @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 + * @throws WebServiceClientException if there is a problem sending or receiving the message + */ + void 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 * WebServiceMessageExtractor. + *

+ * This will only work with a default specified! * * @param requestCallback the requestCallback to be used for manipulating the request message * @param responseExtractor object that will extract results @@ -127,10 +232,39 @@ public interface WebServiceOperations { * Sends a web service message that can be manipulated with the given callback, reading the result with a * WebServiceMessageExtractor. * + * @param uri the URI to send the message to + * @param requestCallback the requestCallback to be used for manipulating the request message + * @param responseExtractor object that will extract results + * @return an arbitrary result object, as returned by the WebServiceMessageExtractor + * @throws WebServiceClientException if there is a problem sending or receiving the message + */ + Object sendAndReceive(String uri, + WebServiceMessageCallback requestCallback, + WebServiceMessageExtractor responseExtractor) throws WebServiceClientException; + + /** + * Sends a web service message that can be manipulated with the given callback, reading the result with a + * WebServiceMessageExtractor. + *

+ * This will only work with a default specified! + * * @param requestCallback the callback to be used for manipulating the request message * @param responseCallback the callback to be used for manipulating the response message * @throws WebServiceClientException if there is a problem sending or receiving the message */ void sendAndReceive(WebServiceMessageCallback requestCallback, WebServiceMessageCallback responseCallback) throws WebServiceClientException; + + /** + * Sends a web service message that can be manipulated with the given callback, reading the result with a + * WebServiceMessageExtractor. + * + * @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 + * @throws WebServiceClientException if there is a problem sending or receiving the message + */ + void 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 efd47e85..206014d0 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,6 +18,8 @@ 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; import javax.xml.transform.Transformer; @@ -35,17 +37,15 @@ import org.springframework.oxm.Marshaller; import org.springframework.oxm.Unmarshaller; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.ObjectUtils; import org.springframework.ws.WebServiceMessage; import org.springframework.ws.WebServiceMessageFactory; 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.context.MessageContext; import org.springframework.ws.transport.FaultAwareWebServiceConnection; import org.springframework.ws.transport.TransportException; -import org.springframework.ws.transport.TransportInputStream; -import org.springframework.ws.transport.TransportOutputStream; import org.springframework.ws.transport.WebServiceConnection; import org.springframework.ws.transport.WebServiceMessageSender; import org.springframework.ws.transport.support.DefaultStrategiesHelper; @@ -69,24 +69,39 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService private FaultResolver faultResolver = new SimpleFaultResolver(); - private DefaultStrategiesHelper defaultStrategiesHelper; + private String defaultUri; /** Creates a new WebServiceTemplate using default settings. */ public WebServiceTemplate() { - Resource resource = new ClassPathResource(ClassUtils.getShortName(getClass()) + ".properties", getClass()); - defaultStrategiesHelper = new DefaultStrategiesHelper(resource); } /** - * Creates a new WebServiceTemplate based on the given message factory and message sender. + * Creates a new WebServiceTemplate based on the given message factory. * * @param messageFactory the message factory to use - * @param messageSender the message sender to use */ - public WebServiceTemplate(WebServiceMessageFactory messageFactory, WebServiceMessageSender messageSender) { - this(); + public WebServiceTemplate(WebServiceMessageFactory messageFactory) { setMessageFactory(messageFactory); - setMessageSender(messageSender); + } + + /** Returns the default URI to be used on operations that do not have a URI parameter. */ + public String getDefaultUri() { + return defaultUri; + } + + /** + * Set the default URI to be used on operations that do not have a URI parameter. + * + * @see #marshalSendAndReceive(Object) + * @see #marshalSendAndReceive(Object,WebServiceMessageCallback) + * @see #sendAndReceive(Source,Result) + * @see #sendAndReceive(Source,WebServiceMessageCallback,Result) + * @see #sendAndReceive(Source,SourceExtractor) + * @see #sendAndReceive(Source,WebServiceMessageCallback,SourceExtractor) + * @see #sendAndReceive(WebServiceMessageCallback,WebServiceMessageCallback) + */ + public void setDefaultUri(String uri) { + this.defaultUri = uri; } /** Returns the marshaller for this template. */ @@ -120,13 +135,19 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService this.faultResolver = faultResolver; } - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + public final void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + Resource resource = new ClassPathResource(ClassUtils.getShortName(getClass()) + ".properties", getClass()); + DefaultStrategiesHelper defaultStrategiesHelper = new DefaultStrategiesHelper(resource); if (getMessageFactory() == null) { - initWebServiceMessageFactory(applicationContext); + initWebServiceMessageFactory(defaultStrategiesHelper, applicationContext); + } + if (ObjectUtils.isEmpty(getMessageSenders())) { + initWebServiceMessageSenders(defaultStrategiesHelper, applicationContext); } } - private void initWebServiceMessageFactory(ApplicationContext applicationContext) + private void initWebServiceMessageFactory(DefaultStrategiesHelper defaultStrategiesHelper, + ApplicationContext applicationContext) throws BeanInitializationException { WebServiceMessageFactory messageFactory = (WebServiceMessageFactory) defaultStrategiesHelper .getDefaultStrategy(WebServiceMessageFactory.class, applicationContext); @@ -144,6 +165,28 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService 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); + } + } + } + setMessageSenders( + (WebServiceMessageSender[]) messageSenders.toArray(new WebServiceMessageSender[messageSenders.size()])); + } + /* * Marshalling methods */ @@ -152,14 +195,24 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService return marshalSendAndReceive(requestPayload, null); } + public Object marshalSendAndReceive(String uri, final Object requestPayload) { + return marshalSendAndReceive(requestPayload, null); + } + public Object marshalSendAndReceive(final Object requestPayload, final WebServiceMessageCallback requestCallback) { + return marshalSendAndReceive(getDefaultUri(), requestPayload, requestCallback); + } + + public Object marshalSendAndReceive(String uri, + final Object requestPayload, + final WebServiceMessageCallback requestCallback) { if (getMarshaller() == null) { throw new IllegalStateException("No marshaller registered. Check configuration of WebServiceTemplate."); } if (getUnmarshaller() == null) { throw new IllegalStateException("No unmarshaller registered. Check configuration of WebServiceTemplate."); } - return sendAndReceive(new WebServiceMessageCallback() { + return sendAndReceive(uri, new WebServiceMessageCallback() { public void doInMessage(WebServiceMessage message) throws IOException { getMarshaller().marshal(requestPayload, message.getPayloadResult()); @@ -183,12 +236,23 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService sendAndReceive(requestPayload, null, responseResult); } + public void sendAndReceive(String uri, Source requestPayload, Result responseResult) { + sendAndReceive(uri, requestPayload, null, responseResult); + } + public void sendAndReceive(Source requestPayload, WebServiceMessageCallback requestCallback, final Result responseResult) { + sendAndReceive(getDefaultUri(), requestPayload, requestCallback, responseResult); + } + + public void sendAndReceive(String uri, + Source requestPayload, + WebServiceMessageCallback requestCallback, + final Result responseResult) { try { final Transformer transformer = createTransformer(); - doSendAndReceive(transformer, requestPayload, requestCallback, new SourceExtractor() { + doSendAndReceive(uri, transformer, requestPayload, requestCallback, new SourceExtractor() { public Object extractData(Source source) throws IOException { try { @@ -214,24 +278,36 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService return sendAndReceive(requestPayload, null, responseExtractor); } + public Object sendAndReceive(String uri, final Source requestPayload, final SourceExtractor responseExtractor) { + return sendAndReceive(uri, requestPayload, null, responseExtractor); + } + public Object sendAndReceive(final Source requestPayload, final WebServiceMessageCallback requestCallback, final SourceExtractor responseExtractor) { + return sendAndReceive(getDefaultUri(), requestPayload, requestCallback, responseExtractor); + } + + public Object sendAndReceive(String uri, + final Source requestPayload, + final WebServiceMessageCallback requestCallback, + final SourceExtractor responseExtractor) { try { - return doSendAndReceive(createTransformer(), requestPayload, requestCallback, responseExtractor); + return doSendAndReceive(uri, createTransformer(), requestPayload, requestCallback, responseExtractor); } catch (TransformerConfigurationException ex) { throw new WebServiceTransformerException("Could not create transformer", ex); } } - private Object doSendAndReceive(final Transformer transformer, + private Object doSendAndReceive(String uri, + final Transformer transformer, final Source requestPayload, final WebServiceMessageCallback requestCallback, final SourceExtractor responseExtractor) { Assert.notNull(responseExtractor, "responseExtractor must not be null"); - return sendAndReceive(new WebServiceMessageCallback() { + return sendAndReceive(uri, new WebServiceMessageCallback() { public void doInMessage(WebServiceMessage message) throws IOException { try { transformer.transform(requestPayload, message.getPayloadResult()); @@ -255,37 +331,40 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService sendAndReceive(requestCallback, new WebServiceMessageCallbackMessageExtractor(responseCallback)); } + public void sendAndReceive(String uri, + WebServiceMessageCallback requestCallback, + WebServiceMessageCallback responseCallback) { + Assert.notNull(responseCallback, "responseCallback must not be null"); + sendAndReceive(uri, requestCallback, new WebServiceMessageCallbackMessageExtractor(responseCallback)); + } + public Object sendAndReceive(WebServiceMessageCallback requestCallback, WebServiceMessageExtractor responseExtractor) { - Assert.notNull(responseExtractor, "response extractor must not be null"); - MessageContext messageContext = createMessageContext(); + return sendAndReceive(getDefaultUri(), requestCallback, responseExtractor); + } + + public Object sendAndReceive(String uri, + WebServiceMessageCallback requestCallback, + WebServiceMessageExtractor responseExtractor) { + Assert.notNull(responseExtractor, "'responseExtractor' must not be null"); + Assert.hasLength(uri, "'uri' must not be empty"); WebServiceConnection connection = null; try { - connection = getMessageSender().createConnection(); - WebServiceMessage request = messageContext.getRequest(); + connection = createConnection(uri); + WebServiceMessage request = getMessageFactory().createWebServiceMessage(); if (requestCallback != null) { requestCallback.doInMessage(request); } - sendRequest(connection, messageContext); - TransportInputStream tis = connection.getTransportInputStream(); - if (tis != null) { - try { - messageContext.readResponse(tis); - logResponse(messageContext); - if (messageContext.hasResponse()) { - WebServiceMessage response = messageContext.getResponse(); - if (!hasFault(connection, messageContext)) { - // normal response - return responseExtractor.extractData(response); - } - else { - // fault response - getFaultResolver().resolveFault(response); - } - } + sendRequest(connection, request); + WebServiceMessage response = receiveResponse(connection); + if (response != null) { + if (!hasFault(connection, response)) { + // normal response + return responseExtractor.extractData(response); } - finally { - tis.close(); + else { + // fault response + getFaultResolver().resolveFault(response); } } return null; @@ -309,48 +388,43 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService } /** Sends the request in the given message context over the connection. */ - private void sendRequest(WebServiceConnection connection, MessageContext messageContext) throws IOException { + private void sendRequest(WebServiceConnection connection, WebServiceMessage request) throws IOException { if (logger.isTraceEnabled()) { ByteArrayOutputStream os = new ByteArrayOutputStream(); - messageContext.getRequest().writeTo(os); + request.writeTo(os); logger.trace("WebServiceTemplate sends request [" + os.toString("UTF-8") + "]"); } else if (logger.isDebugEnabled()) { - logger.debug("WebServiceTemplate sends request [" + messageContext.getRequest() + "]"); + logger.debug("WebServiceTemplate sends request [" + request + "]"); } - TransportOutputStream tos = connection.getTransportOutputStream(); - try { - messageContext.getRequest().writeTo(tos); - tos.flush(); + 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 + "]"); + } } - finally { - tos.close(); + 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, MessageContext messageContext) throws IOException { + private boolean hasFault(WebServiceConnection connection, WebServiceMessage response) throws IOException { if (connection instanceof FaultAwareWebServiceConnection) { return ((FaultAwareWebServiceConnection) connection).hasFault(); } else { - return messageContext.getResponse().hasFault(); - } - } - - private void logResponse(MessageContext messageContext) throws IOException { - if (messageContext.hasResponse()) { - if (logger.isTraceEnabled()) { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - messageContext.getResponse().writeTo(os); - logger.trace("WebServiceTemplate receives response [" + os.toString("UTF-8") + "]"); - } - else if (logger.isDebugEnabled()) { - logger.debug("WebServiceTemplate receives response [" + messageContext.getRequest() + "]"); - } - } - else if (logger.isDebugEnabled()) { - logger.debug("WebServiceTemplate receives no response for request [" + messageContext.getRequest() + "]"); + return response.hasFault(); } } 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 86f0ddf9..c2ecfc0c 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 @@ -26,24 +26,19 @@ import org.springframework.oxm.Marshaller; import org.springframework.oxm.Unmarshaller; import org.springframework.ws.WebServiceMessageFactory; import org.springframework.ws.client.core.WebServiceTemplate; -import org.springframework.ws.transport.WebServiceMessageSender; /** * Convenient super class for application classes that need Web service access. *

- * Requires a {@link org.springframework.ws.WebServiceMessageFactory} and {@link org.springframework.ws.transport.WebServiceMessageSender}, - * or a {@link org.springframework.ws.client.core.WebServiceTemplate} instance to be set. It will create its own - * WebServiceTemplate if WebServiceMessageFactory and WebServiceMessageSender are - * passed in. + * Requires a {@link WebServiceMessageFactory} or a {@link WebServiceTemplate} instance to be set. It will create its + * own WebServiceTemplate if WebServiceMessageFactory is passed in. *

- * In addition to the message factory and sender properties, this gateway offers {@link - * org.springframework.oxm.Marshaller} and {@link org.springframework.oxm.Unmarshaller} properties. Setting these is - * required when the {@link org.springframework.ws.client.core.WebServiceTemplate#marshalSendAndReceive(Object) - * marshalling methods} of the template are to be used. + * In addition to the message factory property, this gateway offers {@link Marshaller} and {@link Unmarshaller} + * properties. Setting these is required when the {@link WebServiceTemplate#marshalSendAndReceive(Object) marshalling + * methods} of the template are to be used. * * @author Arjen Poutsma * @see #setMessageFactory(org.springframework.ws.WebServiceMessageFactory) - * @see #setMessageSender(org.springframework.ws.transport.WebServiceMessageSender) * @see org.springframework.ws.client.core.WebServiceTemplate * @see #setMarshaller(org.springframework.oxm.Marshaller) */ @@ -63,14 +58,12 @@ public abstract class WebServiceGatewaySupport implements InitializingBean, Appl } /** - * Creates a new WebServiceGatewaySupport instance based on the given message factory and message - * sender. + * Creates a new WebServiceGatewaySupport instance based on the given message factory. * * @param messageFactory the message factory to use - * @param messageSender the message sender to use */ - protected WebServiceGatewaySupport(WebServiceMessageFactory messageFactory, WebServiceMessageSender messageSender) { - webServiceTemplate = new WebServiceTemplate(messageFactory, messageSender); + protected WebServiceGatewaySupport(WebServiceMessageFactory messageFactory) { + webServiceTemplate = new WebServiceTemplate(messageFactory); } /** Returns the WebServiceMessageFactory used by the gateway. */ @@ -83,14 +76,14 @@ public abstract class WebServiceGatewaySupport implements InitializingBean, Appl webServiceTemplate.setMessageFactory(messageFactory); } - /** Returns the WebServiceMessageSender used by the gateway. */ - public final WebServiceMessageSender getMessageSender() { - return webServiceTemplate.getMessageSender(); + /** Returns the default URI used by the gateway. */ + public final String getDefaultUri() { + return webServiceTemplate.getDefaultUri(); } - /** Sets the WebServiceMessageSender to be used by the gateway. */ - public final void setMessageSender(WebServiceMessageSender messageSender) { - webServiceTemplate.setMessageSender(messageSender); + /** Sets the default URI used by the gateway. */ + public final void setDefaultUri(String uri) { + webServiceTemplate.setDefaultUri(uri); } /** Returns the WebServiceTemplate for the gateway. */ 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 e26c2b9a..b38e58db 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 @@ -16,17 +16,18 @@ package org.springframework.ws.client.support; +import java.io.IOException; + import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; import org.springframework.ws.WebServiceMessageFactory; -import org.springframework.ws.context.DefaultMessageContext; -import org.springframework.ws.context.MessageContext; +import org.springframework.ws.transport.WebServiceConnection; import org.springframework.ws.transport.WebServiceMessageSender; import org.springframework.xml.transform.TransformerObjectSupport; /** * Base class for WebServiceTemplate and other WS-accessing helpers. Defines common properties like the - * {@link org.springframework.ws.WebServiceMessageFactory} and {@link org.springframework.ws.transport.WebServiceMessageSender}. + * {@link WebServiceMessageFactory} and {@link WebServiceMessageSender}. *

* Not intended to be used directly. See {@link org.springframework.ws.client.core.WebServiceTemplate}. * @@ -37,48 +38,58 @@ public abstract class WebServiceAccessor extends TransformerObjectSupport implem private WebServiceMessageFactory messageFactory; - private WebServiceMessageSender messageSender; + private WebServiceMessageSender[] messageSenders; - /** - * Returns the message factory used for creating messages. - */ + /** Returns the message factory used for creating messages. */ public WebServiceMessageFactory getMessageFactory() { return messageFactory; } - /** - * Sets the message factory used for creating messages. - */ + /** Sets the message factory used for creating messages. */ public void setMessageFactory(WebServiceMessageFactory messageFactory) { this.messageFactory = messageFactory; } - /** - * Returns the message sender. - */ - public WebServiceMessageSender getMessageSender() { - return messageSender; + /** Returns the message senders used for sending messages. */ + public WebServiceMessageSender[] getMessageSenders() { + return messageSenders; } - /** - * Sets the message sender. - */ public void setMessageSender(WebServiceMessageSender messageSender) { - this.messageSender = messageSender; + Assert.notNull(messageSender, "'messageSender' must not be null"); + this.messageSenders = new WebServiceMessageSender[]{messageSender}; } - /** - * Returns a MessageContext with an empty message, and the defined - * WebServiceMessageFactory. - * - * @return the created message context - */ - protected MessageContext createMessageContext() { - return new DefaultMessageContext(getMessageFactory()); + public void setMessageSenders(WebServiceMessageSender[] messageSenders) { + Assert.notEmpty(messageSenders, "'messageSenders' must not be empty"); + this.messageSenders = messageSenders; } public void afterPropertiesSet() throws Exception { - Assert.notNull(getMessageFactory(), "messageFactory is required"); - Assert.notNull(getMessageSender(), "messageSender is required"); + Assert.notNull(getMessageFactory(), "Property 'messageFactory' is required"); + Assert.notEmpty(getMessageSenders(), "Property 'messageSenders' is required"); } + + /** + * Creates a connection to the given URI, or throws an exception when it cannot be resolved. + * + * @param uri the URI to open a connection to + * @return the created connection + * @throws IllegalArgumentException when the uri cannot be resolved + * @throws IOException when an I/O error occurs + */ + protected WebServiceConnection createConnection(String uri) throws IOException { + Assert.notEmpty(getMessageSenders(), "Property 'messageSenders' is required"); + WebServiceMessageSender messageSender = null; + WebServiceMessageSender[] messageSenders = getMessageSenders(); + for (int i = 0; i < messageSenders.length; i++) { + if (messageSenders[i].supports(uri)) { + messageSender = messageSenders[i]; + break; + } + } + Assert.notNull(messageSender, "Could not resolve [" + uri + "] to a WebServiceMessageSender"); + return messageSender.createConnection(uri); + } + } diff --git a/core/src/main/java/org/springframework/ws/client/support/package.html b/core/src/main/java/org/springframework/ws/client/support/package.html new file mode 100644 index 00000000..edee4deb --- /dev/null +++ b/core/src/main/java/org/springframework/ws/client/support/package.html @@ -0,0 +1,6 @@ + + +Classes supporting the org.springframework.ws.client.core package. +Contains a base class for WebServiceTemplate usage. + + \ No newline at end of file diff --git a/core/src/main/java/org/springframework/ws/transport/AbstractReceivingWebServiceConnection.java b/core/src/main/java/org/springframework/ws/transport/AbstractReceiverConnection.java similarity index 81% rename from core/src/main/java/org/springframework/ws/transport/AbstractReceivingWebServiceConnection.java rename to core/src/main/java/org/springframework/ws/transport/AbstractReceiverConnection.java index ac067ec4..b8dac276 100644 --- a/core/src/main/java/org/springframework/ws/transport/AbstractReceivingWebServiceConnection.java +++ b/core/src/main/java/org/springframework/ws/transport/AbstractReceiverConnection.java @@ -21,32 +21,25 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.Iterator; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - /** - * Abstract base class for {@link org.springframework.ws.transport.WebServiceConnection} implementations used for - * sending requests. + * Abstract base class for {@link WebServiceConnection} implementations used for receiving requests. * * @author Arjen Poutsma */ -public abstract class AbstractReceivingWebServiceConnection implements WebServiceConnection { - - /** Logger available to subclasses. */ - protected final Log logger = LogFactory.getLog(getClass()); +public abstract class AbstractReceiverConnection extends AbstractWebServiceConnection { private TransportInputStream requestInputStream; private TransportOutputStream responseOutputStream; - public final TransportInputStream getTransportInputStream() throws IOException { + protected final TransportInputStream createTransportInputStream() throws IOException { if (requestInputStream == null) { requestInputStream = new RequestTransportInputStream(); } return requestInputStream; } - public final TransportOutputStream getTransportOutputStream() throws IOException { + protected final TransportOutputStream createTransportOutputStream() throws IOException { if (responseOutputStream == null) { responseOutputStream = new ResponseTransportOutputStream(); } @@ -80,9 +73,6 @@ public abstract class AbstractReceivingWebServiceConnection implements WebServic /** Returns the output stream to write the request to. */ protected abstract OutputStream getResponseOutputStream() throws IOException; - /** Sends the response. Called when the {@link ResponseTransportOutputStream#close() is closed}. */ - protected abstract void sendResponse() throws IOException; - /** Implementation of TransportInputStream for receiving-side connections. */ private class RequestTransportInputStream extends TransportInputStream { @@ -113,7 +103,6 @@ public abstract class AbstractReceivingWebServiceConnection implements WebServic public void close() throws IOException { super.close(); - sendResponse(); } } diff --git a/core/src/main/java/org/springframework/ws/transport/AbstractSendingWebServiceConnection.java b/core/src/main/java/org/springframework/ws/transport/AbstractSenderConnection.java similarity index 83% rename from core/src/main/java/org/springframework/ws/transport/AbstractSendingWebServiceConnection.java rename to core/src/main/java/org/springframework/ws/transport/AbstractSenderConnection.java index e3ab565e..60aea67a 100644 --- a/core/src/main/java/org/springframework/ws/transport/AbstractSendingWebServiceConnection.java +++ b/core/src/main/java/org/springframework/ws/transport/AbstractSenderConnection.java @@ -21,31 +21,25 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.Iterator; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - /** * Abstract base class for {@link WebServiceConnection} implementations used for sending requests. * * @author Arjen Poutsma */ -public abstract class AbstractSendingWebServiceConnection implements WebServiceConnection { - - /** Logger available to subclasses. */ - protected final Log logger = LogFactory.getLog(getClass()); +public abstract class AbstractSenderConnection extends AbstractWebServiceConnection { private TransportOutputStream requestOutputStream; private TransportInputStream responseInputStream; - public final TransportOutputStream getTransportOutputStream() throws IOException { + protected final TransportOutputStream createTransportOutputStream() throws IOException { if (requestOutputStream == null) { requestOutputStream = new RequestTransportOutputStream(); } return requestOutputStream; } - public final TransportInputStream getTransportInputStream() throws IOException { + protected final TransportInputStream createTransportInputStream() throws IOException { if (hasResponse()) { if (responseInputStream == null) { responseInputStream = new ResponseTransportInputStream(); @@ -72,9 +66,6 @@ public abstract class AbstractSendingWebServiceConnection implements WebServiceC /** Returns the output stream to write the request to. */ protected abstract OutputStream getRequestOutputStream() throws IOException; - /** Sends the request. Called when the {@link RequestTransportOutputStream#close() is closed}. */ - protected abstract void sendRequest() throws IOException; - /** * Returns an iteration over all the header names this request contains. Returns an empty Iterator if * there areno headers. @@ -100,11 +91,6 @@ public abstract class AbstractSendingWebServiceConnection implements WebServiceC protected OutputStream createOutputStream() throws IOException { return getRequestOutputStream(); } - - public void close() throws IOException { - super.close(); - sendRequest(); - } } /** Implementation of {@link TransportInputStream} for client-side HTTP. */ diff --git a/core/src/main/java/org/springframework/ws/transport/AbstractWebServiceConnection.java b/core/src/main/java/org/springframework/ws/transport/AbstractWebServiceConnection.java new file mode 100644 index 00000000..c67ee052 --- /dev/null +++ b/core/src/main/java/org/springframework/ws/transport/AbstractWebServiceConnection.java @@ -0,0 +1,102 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.transport; + +import java.io.IOException; + +import org.springframework.ws.WebServiceMessage; +import org.springframework.ws.WebServiceMessageFactory; + +/** + * Abstract base class for {@link WebServiceConnection} implementations. + * + * @author Arjen Poutsma + */ +public abstract class AbstractWebServiceConnection implements WebServiceConnection { + + public final void send(WebServiceMessage message) throws IOException { + TransportOutputStream tos = createTransportOutputStream(); + try { + message.writeTo(tos); + tos.flush(); + } + finally { + tos.close(); + } + onSend(message); + } + + public final WebServiceMessage receive(WebServiceMessageFactory messageFactory) throws IOException { + TransportInputStream tis = createTransportInputStream(); + if (tis == null) { + return null; + } + WebServiceMessage message = null; + try { + message = messageFactory.createWebServiceMessage(tis); + } + finally { + tis.close(); + } + onReceive(message); + return message; + } + + /** + * Returns a TransportOutputStream for the given message. Called from {@link + * #send(WebServiceMessage)}. + * + * @return the output stream + * @throws IOException when an I/O exception occurs + */ + protected abstract TransportOutputStream createTransportOutputStream() throws IOException; + + /** + * Called when the given message has been written to the TransportOutputStream. Called from {@link + * #send(WebServiceMessage)}. + *

+ * Default implementation does nothing. + * + * @param message the message + * @throws IOException when an I/O exception occurs + */ + protected void onSend(WebServiceMessage message) throws IOException { + + } + + /** + * Returns a TransportInputStream. Called from {@link #receive(WebServiceMessageFactory)}. + * + * @return the input stream, or null if no response can be read + * @throws IOException when an I/O exception occurs + */ + protected abstract TransportInputStream createTransportInputStream() throws IOException; + + /** + * Called when the given message has been written to the TransportOutputStream. Called from {@link + * #receive(WebServiceMessageFactory)}. + *

+ * Default implementation does nothing. + * + * @param message the message + * @throws IOException when an I/O exception occurs + */ + protected void onReceive(WebServiceMessage message) throws IOException { + + } + +} diff --git a/core/src/main/java/org/springframework/ws/transport/EndpointAwareWebServiceConnection.java b/core/src/main/java/org/springframework/ws/transport/EndpointAwareWebServiceConnection.java new file mode 100644 index 00000000..1337ad7e --- /dev/null +++ b/core/src/main/java/org/springframework/ws/transport/EndpointAwareWebServiceConnection.java @@ -0,0 +1,33 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.transport; + +import org.springframework.ws.NoEndpointFoundException; + +/** + * Sub-interface of {@link WebServiceConnection} that is aware of any server-side situations where an endpoint is not + * found. Typically, this results in a special error codes. + * + * @author Arjen Poutsma + * @see NoEndpointFoundException + */ +public interface EndpointAwareWebServiceConnection extends WebServiceConnection { + + /** Called when an endpoint is not found. */ + void endpointNotFound(); + +} 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 12b8baca..7ac0d1ba 100644 --- a/core/src/main/java/org/springframework/ws/transport/WebServiceConnection.java +++ b/core/src/main/java/org/springframework/ws/transport/WebServiceConnection.java @@ -19,59 +19,43 @@ package org.springframework.ws.transport; import java.io.IOException; import org.springframework.ws.WebServiceMessage; -import org.springframework.ws.transport.http.HttpServletConnection; +import org.springframework.ws.WebServiceMessageFactory; /** * Represents a point-to-point connection that a client can use for sending {@link WebServiceMessage} objects directly * to a remote party. *

* A WebServiceConnection can be obtained using a {@link WebServiceMessageSender}. - *

- * On the receiving side, the typical usage scenario for this connection is:

  1. Create concrete connection - * implementation (eg. {@link HttpServletConnection})
  2. Read request from {@link #getTransportInputStream() the input - * stream}.
  3. {@link TransportInputStream#close() Close} the input stream
  4. Write response to {@link - * #getTransportOutputStream() the output stream}.
  5. {@link TransportOutputStream#flush() Flush} the output stream - *
  6. {@link TransportOutputStream#close() Close} the output stream
  7. {@link #close() Close the connection}
- *

- * On the sending side, the typical usage scenario for this connection is:

  1. Create connection with {@link - * WebServiceMessageSender#createConnection()}
  2. Write request to {@link #getTransportOutputStream() the output - * stream}.
  3. {@link TransportOutputStream#flush() Flush} the output stream
  4. {@link TransportOutputStream#close() - * Close} the output stream
  5. Read request from {@link #getTransportInputStream() the input stream}.
  6. {@link - * TransportInputStream#close() Close} the input stream
  7. {@link #close() Close the connection}
* * @author Arjen Poutsma - * @see WebServiceMessageSender#createConnection() - * @see #getTransportInputStream() - * @see #getTransportOutputStream() + * @see WebServiceMessageSender#createConnection(String) */ public interface WebServiceConnection { /** - * Returns a transport input stream for this connection. - *

- * Returns null if no transport input stream is available (eg. a request might not have a response). + * Sends the given message using this connection. * - * @return a transport input stream for this connection, or null - * @throws IOException if an I/O error occurs when creating the input stream, the connection is closed + * @param message the message to be sent + * @throws IOException in case of I/O errors */ - TransportInputStream getTransportInputStream() throws IOException; + void send(WebServiceMessage message) throws IOException; /** - * Returns a transport output stream for this connection. - *

- * Returns null if no transport output stream is available (eg. a response might not have a response). + * Receives a message using the given {@link WebServiceMessageFactory}. This method blocks until it receives, or + * returns null when no message is received. * - * @return a transport output stream for this connection - * @throws IOException if an I/O error occurs when creating the output stream, the connection is closed + * @param messageFactory the message factory used for reading messages + * @return the read message, or null if no message received + * @throws IOException in case of I/O errors */ - TransportOutputStream getTransportOutputStream() throws IOException; + WebServiceMessage receive(WebServiceMessageFactory messageFactory) throws IOException; /** * Closes this connection. *

* Once a connection has been closed, it is not available for further use. A new connection needs to be created. * - * @throws IOException if an I/O error occurs when closing this socket + * @throws IOException if an I/O error occurs when closing this connection */ void close() throws IOException; diff --git a/core/src/main/java/org/springframework/ws/transport/WebServiceMessageSender.java b/core/src/main/java/org/springframework/ws/transport/WebServiceMessageSender.java index 2ce3b174..7a0f8e0c 100644 --- a/core/src/main/java/org/springframework/ws/transport/WebServiceMessageSender.java +++ b/core/src/main/java/org/springframework/ws/transport/WebServiceMessageSender.java @@ -2,9 +2,11 @@ package org.springframework.ws.transport; import java.io.IOException; +import org.springframework.ws.WebServiceMessage; + /** - * Defines the methods for classes capable of sending and receiving {@link org.springframework.ws.WebServiceMessage} - * instances across a transport. + * Defines the methods for classes capable of sending and receiving {@link WebServiceMessage} instances across a + * transport. *

* The WebServiceMessageSender is basically a factory for {@link WebServiceConnection} objects. * @@ -14,11 +16,20 @@ import java.io.IOException; public interface WebServiceMessageSender { /** - * Create a new WebServiceConnection. + * Create a new {@link WebServiceConnection} to the specified URI. * + * @param uri the URI to open a connection to * @return the new connection * @throws IOException in case of I/O errors */ - WebServiceConnection createConnection() throws IOException; + WebServiceConnection createConnection(String uri) throws IOException; + + /** + * Indicates whether the message sender supports the given URI. + * + * @param uri the URI + * @return true + */ + boolean supports(String uri); } diff --git a/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpSendingWebServiceConnection.java b/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpSenderConnection.java similarity index 94% rename from core/src/main/java/org/springframework/ws/transport/http/AbstractHttpSendingWebServiceConnection.java rename to core/src/main/java/org/springframework/ws/transport/http/AbstractHttpSenderConnection.java index 80059ae3..c5a4984d 100644 --- a/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpSendingWebServiceConnection.java +++ b/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpSenderConnection.java @@ -23,7 +23,7 @@ import java.util.Iterator; import java.util.zip.GZIPInputStream; import org.springframework.util.FileCopyUtils; -import org.springframework.ws.transport.AbstractSendingWebServiceConnection; +import org.springframework.ws.transport.AbstractSenderConnection; import org.springframework.ws.transport.FaultAwareWebServiceConnection; import org.springframework.ws.transport.WebServiceConnection; @@ -32,7 +32,7 @@ import org.springframework.ws.transport.WebServiceConnection; * * @author Arjen Poutsma */ -public abstract class AbstractHttpSendingWebServiceConnection extends AbstractSendingWebServiceConnection +public abstract class AbstractHttpSenderConnection extends AbstractSenderConnection implements FaultAwareWebServiceConnection { protected static final String HTTP_HEADER_CONTENT_ENCODING = "Content-Encoding"; diff --git a/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSender.java b/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSender.java index 6f5861b4..e6a86100 100644 --- a/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSender.java +++ b/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSender.java @@ -16,10 +16,7 @@ package org.springframework.ws.transport.http; -import java.net.URL; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.Assert; +import org.springframework.util.StringUtils; import org.springframework.ws.transport.WebServiceMessageSender; /** @@ -28,9 +25,7 @@ import org.springframework.ws.transport.WebServiceMessageSender; * * @author Arjen Poutsma */ -public abstract class AbstractHttpWebServiceMessageSender implements WebServiceMessageSender, InitializingBean { - - private URL url; +public abstract class AbstractHttpWebServiceMessageSender implements WebServiceMessageSender { private boolean acceptGzipEncoding = true; @@ -38,15 +33,9 @@ public abstract class AbstractHttpWebServiceMessageSender implements WebServiceM protected static final String ENCODING_GZIP = "gzip"; - /** Returns the url used by this message sender. */ - public URL getUrl() { - return url; - } + protected static final String HTTP_SCHEME = "http://"; - /** Sets the url used by this message sender. */ - public void setUrl(URL url) { - this.url = url; - } + protected static final String HTTPS_SCHEME = "https://"; /** * Return whether to accept GZIP encoding, that is, whether to send the HTTP Accept-Encoding header @@ -67,8 +56,7 @@ public abstract class AbstractHttpWebServiceMessageSender implements WebServiceM this.acceptGzipEncoding = acceptGzipEncoding; } - public void afterPropertiesSet() throws Exception { - Assert.notNull(url, "url is required"); + public boolean supports(String uri) { + return StringUtils.hasLength(uri) && (uri.startsWith(HTTP_SCHEME) || uri.startsWith(HTTPS_SCHEME)); } - } 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 a8377c90..50e1ffa7 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 @@ -29,6 +29,7 @@ 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; +import org.springframework.ws.WebServiceMessage; import org.springframework.ws.transport.WebServiceConnection; /** @@ -37,7 +38,7 @@ import org.springframework.ws.transport.WebServiceConnection; * * @author Arjen Poutsma */ -public class CommonsHttpConnection extends AbstractHttpSendingWebServiceConnection { +public class CommonsHttpConnection extends AbstractHttpSenderConnection { private final HttpClient httpClient; @@ -52,6 +53,10 @@ public class CommonsHttpConnection extends AbstractHttpSendingWebServiceConnecti this.postMethod = postMethod; } + public PostMethod getPostMethod() { + return postMethod; + } + public void close() throws IOException { postMethod.releaseConnection(); } @@ -64,7 +69,7 @@ public class CommonsHttpConnection extends AbstractHttpSendingWebServiceConnecti return bufferedOutput; } - protected void sendRequest() throws IOException { + protected void onSend(WebServiceMessage message) throws IOException { postMethod.setRequestEntity(new ByteArrayRequestEntity(bufferedOutput.toByteArray())); bufferedOutput = null; httpClient.executeMethod(postMethod); diff --git a/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpMessageSender.java b/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpMessageSender.java index 467da065..fc2ab909 100644 --- a/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpMessageSender.java +++ b/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpMessageSender.java @@ -78,8 +78,8 @@ public class CommonsHttpMessageSender extends AbstractHttpWebServiceMessageSende this.httpClient = httpClient; } - public WebServiceConnection createConnection() throws IOException { - PostMethod postMethod = new PostMethod(getUrl().toString()); + public WebServiceConnection createConnection(String uri) throws IOException { + PostMethod postMethod = new PostMethod(uri); if (isAcceptGzipEncoding()) { postMethod.addRequestHeader(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP); } 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 152820ee..a223a65f 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 @@ -23,7 +23,9 @@ import java.util.Iterator; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.springframework.ws.transport.AbstractReceivingWebServiceConnection; +import org.springframework.ws.WebServiceMessage; +import org.springframework.ws.transport.AbstractReceiverConnection; +import org.springframework.ws.transport.EndpointAwareWebServiceConnection; import org.springframework.ws.transport.WebServiceConnection; import org.springframework.ws.transport.support.EnumerationIterator; @@ -32,57 +34,73 @@ import org.springframework.ws.transport.support.EnumerationIterator; * * @author Arjen Poutsma */ -public class HttpServletConnection extends AbstractReceivingWebServiceConnection { +public class HttpServletConnection extends AbstractReceiverConnection implements EndpointAwareWebServiceConnection { - private final HttpServletRequest request; + private final HttpServletRequest httpServletRequest; - private final HttpServletResponse response; + private final HttpServletResponse httpServletResponse; + + private boolean sentResponse = false; + + private boolean endpointFound = true; /** * Constructs a new servlet connection with the given HttpServletRequest and * HttpServletResponse. */ public HttpServletConnection(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) { - request = httpServletRequest; - response = httpServletResponse; + this.httpServletRequest = httpServletRequest; + this.httpServletResponse = httpServletResponse; + } + + public void close() throws IOException { + if (!sentResponse && endpointFound) { + httpServletResponse.setStatus(HttpServletResponse.SC_ACCEPTED); + } } /** Returns the HttpServletRequest for this connection. */ public HttpServletRequest getHttpServletRequest() { - return request; + return httpServletRequest; } /** Returns the HttpServletResponse for this connection. */ public HttpServletResponse getHttpServletResponse() { - return response; + return httpServletResponse; + } + + public void endpointNotFound() { + endpointFound = false; + httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND); } protected Iterator getRequestHeaderNames() throws IOException { - return new EnumerationIterator(request.getHeaderNames()); + return new EnumerationIterator(httpServletRequest.getHeaderNames()); } protected Iterator getRequestHeaders(String name) throws IOException { - return new EnumerationIterator(request.getHeaders(name)); + return new EnumerationIterator(httpServletRequest.getHeaders(name)); } protected InputStream getRequestInputStream() throws IOException { - return request.getInputStream(); + return httpServletRequest.getInputStream(); } protected void addResponseHeader(String name, String value) throws IOException { - response.addHeader(name, value); + httpServletResponse.addHeader(name, value); } protected OutputStream getResponseOutputStream() throws IOException { - return response.getOutputStream(); + return httpServletResponse.getOutputStream(); } - protected void sendResponse() throws IOException { - // no op + protected void onSend(WebServiceMessage message) throws IOException { + sentResponse = true; + if (!message.hasFault()) { + httpServletResponse.setStatus(HttpServletResponse.SC_OK); + } + else { + httpServletResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } } - - public void close() throws IOException { - // no op - } - } 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 d0e5a7a1..ae26bc19 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 @@ -28,6 +28,7 @@ import java.util.Set; import org.springframework.util.Assert; import org.springframework.util.StringUtils; +import org.springframework.ws.WebServiceMessage; import org.springframework.ws.transport.WebServiceConnection; /** @@ -35,7 +36,7 @@ import org.springframework.ws.transport.WebServiceConnection; * * @author Arjen Poutsma */ -public class HttpUrlConnection extends AbstractHttpSendingWebServiceConnection { +public class HttpUrlConnection extends AbstractHttpSenderConnection { private final HttpURLConnection connection; @@ -49,6 +50,10 @@ public class HttpUrlConnection extends AbstractHttpSendingWebServiceConnection { this.connection = connection; } + public HttpURLConnection getConnection() { + return connection; + } + public void close() { connection.disconnect(); } @@ -61,7 +66,7 @@ public class HttpUrlConnection extends AbstractHttpSendingWebServiceConnection { return connection.getOutputStream(); } - protected void sendRequest() throws IOException { + protected void onSend(WebServiceMessage message) throws IOException { connection.connect(); } @@ -111,5 +116,4 @@ public class HttpUrlConnection extends AbstractHttpSendingWebServiceConnection { connection.getResponseCode() + ", status message = [" + connection.getResponseMessage() + "]"); } } - } diff --git a/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSender.java b/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSender.java index 347c3054..bd87664a 100644 --- a/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSender.java +++ b/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSender.java @@ -18,6 +18,7 @@ package org.springframework.ws.transport.http; import java.io.IOException; import java.net.HttpURLConnection; +import java.net.URL; import java.net.URLConnection; import org.springframework.ws.transport.WebServiceConnection; @@ -27,8 +28,8 @@ import org.springframework.ws.transport.WebServiceConnection; * without support for HTTP authentication or advanced configuration options. *

* Designed for easy subclassing, customizing specific template methods. However, consider {@link - * org.springframework.ws.transport.http.CommonsHttpMessageSender} for more sophisticated needs: the J2SE - * HttpURLConnection is rather limited in its capabilities. + * CommonsHttpMessageSender} for more sophisticated needs: the J2SE HttpURLConnection is rather limited in + * its capabilities. * * @author Arjen Poutsma * @see java.net.HttpURLConnection @@ -37,10 +38,11 @@ public class HttpUrlConnectionMessageSender extends AbstractHttpWebServiceMessag private static final String HTTP_METHOD_POST = "POST"; - public WebServiceConnection createConnection() throws IOException { - URLConnection connection = getUrl().openConnection(); + public WebServiceConnection createConnection(String uri) throws IOException { + URL url = new URL(uri); + URLConnection connection = url.openConnection(); if (!(connection instanceof HttpURLConnection)) { - throw new HttpTransportException("URL [" + getUrl() + "] is not an HTTP URL"); + throw new HttpTransportException("URI [" + uri + "] is not an HTTP URL"); } else { HttpURLConnection httpURLConnection = (HttpURLConnection) connection; diff --git a/core/src/main/java/org/springframework/ws/transport/http/WebServiceMessageReceiverHandlerAdapter.java b/core/src/main/java/org/springframework/ws/transport/http/WebServiceMessageReceiverHandlerAdapter.java index e0ae2366..820c9c5e 100644 --- a/core/src/main/java/org/springframework/ws/transport/http/WebServiceMessageReceiverHandlerAdapter.java +++ b/core/src/main/java/org/springframework/ws/transport/http/WebServiceMessageReceiverHandlerAdapter.java @@ -21,7 +21,6 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.ModelAndView; -import org.springframework.ws.WebServiceMessage; import org.springframework.ws.transport.WebServiceConnection; import org.springframework.ws.transport.WebServiceMessageReceiver; import org.springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport; @@ -67,30 +66,4 @@ public class WebServiceMessageReceiverHandlerAdapter extends WebServiceMessageRe return handler instanceof WebServiceMessageReceiver; } - /** Sets the response code to 204, Accepted. */ - protected void handleNoResponse(WebServiceConnection connection) { - HttpServletResponse httpServletResponse = ((HttpServletConnection) connection).getHttpServletResponse(); - httpServletResponse.setStatus(HttpServletResponse.SC_ACCEPTED); - } - - /** - * Sets the response code to 200, OK, for normal responses. Set the code to 500, Internal Server Error, in case of a - * SOAP Fault, - */ - protected void handleResponse(WebServiceConnection connection, WebServiceMessage response) throws Exception { - HttpServletResponse httpServletResponse = ((HttpServletConnection) connection).getHttpServletResponse(); - if (response.hasFault()) { - httpServletResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - else { - httpServletResponse.setStatus(HttpServletResponse.SC_OK); - } - super.handleResponse(connection, response); - } - - /** Sets the response code to 404, Not Found. */ - protected void handleNoEndpointFound(WebServiceConnection connection) { - HttpServletResponse httpServletResponse = ((HttpServletConnection) connection).getHttpServletResponse(); - httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND); - } } 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 f2c4cb7e..1c646ed2 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 @@ -27,8 +27,7 @@ import org.springframework.ws.WebServiceMessage; import org.springframework.ws.WebServiceMessageFactory; import org.springframework.ws.context.DefaultMessageContext; import org.springframework.ws.context.MessageContext; -import org.springframework.ws.transport.TransportInputStream; -import org.springframework.ws.transport.TransportOutputStream; +import org.springframework.ws.transport.EndpointAwareWebServiceConnection; import org.springframework.ws.transport.WebServiceConnection; import org.springframework.ws.transport.WebServiceMessageReceiver; import org.springframework.ws.transport.context.DefaultTransportContext; @@ -80,17 +79,17 @@ public abstract class WebServiceMessageReceiverObjectSupport implements Initiali TransportContextHolder.setTransportContext(new DefaultTransportContext(connection)); try { - MessageContext messageContext = handleRequest(connection); + WebServiceMessage request = connection.receive(getMessageFactory()); + MessageContext messageContext = new DefaultMessageContext(request, getMessageFactory()); receiver.receive(messageContext); - if (!messageContext.hasResponse()) { - handleNoResponse(connection); - } - else { - handleResponse(connection, messageContext.getResponse()); + if (messageContext.hasResponse()) { + connection.send(request); } } catch (NoEndpointFoundException ex) { - handleNoEndpointFound(connection); + if (connection instanceof EndpointAwareWebServiceConnection) { + ((EndpointAwareWebServiceConnection) connection).endpointNotFound(); + } } finally { try { @@ -103,53 +102,4 @@ public abstract class WebServiceMessageReceiverObjectSupport implements Initiali } } - private MessageContext handleRequest(WebServiceConnection connection) throws IOException { - TransportInputStream tis = connection.getTransportInputStream(); - try { - WebServiceMessage messageRequest = getMessageFactory().createWebServiceMessage(tis); - return new DefaultMessageContext(messageRequest, getMessageFactory()); - } - finally { - tis.close(); - } - } - - /** - * Invoked from {@link #handleConnection} when no response is given. Default implementation does nothing. Can be - * overriden to set certain transport-specific response headers. - * - * @param connection the incoming connection - */ - protected void handleNoResponse(WebServiceConnection connection) { - } - - /** - * Handles the sending of the response. Invoked from {@link #handleConnection}. Default implementation writes the - * given response to the given TransportOutputStream. Can be overriden to set certain - * transport-specific headers. - * - * @param connection the incoming connection - * @param response the response message - * @see WebServiceMessage#writeTo(java.io.OutputStream) - */ - protected void handleResponse(WebServiceConnection connection, WebServiceMessage response) throws Exception { - TransportOutputStream tos = connection.getTransportOutputStream(); - try { - response.writeTo(tos); - tos.flush(); - } - finally { - tos.close(); - } - } - - /** - * Invoked from {@link #handleConnection} when no suitable endpoint is found. Default implementation does nothing. - * Can be overriden to set certain transport-specific response headers. - * - * @param connection the incoming connection - */ - protected void handleNoEndpointFound(WebServiceConnection connection) { - } - } diff --git a/core/src/main/java/org/springframework/ws/transport/support/package.html b/core/src/main/java/org/springframework/ws/transport/support/package.html new file mode 100644 index 00000000..7b03a3fe --- /dev/null +++ b/core/src/main/java/org/springframework/ws/transport/support/package.html @@ -0,0 +1,5 @@ + + +Classes supporting the org.springframework.ws.transport package. + + \ No newline at end of file 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 2b4a00a6..539831b6 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,4 +1,5 @@ # Default implementation classes for WebServiceTemplate's strategy interfaces. # Not meant to be customized by application developers. -org.springframework.ws.WebServiceMessageFactory=org.springframework.ws.soap.saaj.SaajSoapMessageFactory \ No newline at end of file +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/SimpleSaajServlet.java b/core/src/test/java/org/springframework/ws/client/core/SimpleSaajServlet.java index c4057aa1..13bd7f77 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 @@ -99,15 +99,18 @@ public class SimpleSaajServlet extends HttpServlet { MimeHeaders headers = getHeaders(req); SOAPMessage msg = msgFactory.createMessage(headers, req.getInputStream()); SOAPMessage reply = onMessage(msg); - resp.setStatus(HttpServletResponse.SC_OK); if (reply != null) { if (reply.saveRequired()) { reply.saveChanges(); } - resp.setStatus(HttpServletResponse.SC_OK); + 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()); 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 95fef487..09d16df4 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,7 +16,6 @@ package org.springframework.ws.client.core; -import java.net.URL; import javax.xml.soap.MessageFactory; import org.custommonkey.xmlunit.XMLTestCase; @@ -40,9 +39,8 @@ public class WebServiceTemplateIntegrationTest extends XMLTestCase { jettyContext.addServlet(SimpleSaajServlet.class, "/"); jettyServer.start(); template = new WebServiceTemplate(); - HttpUrlConnectionMessageSender messageSender = new HttpUrlConnectionMessageSender(); - messageSender.setUrl(new URL("http://localhost:8888/")); - template.setMessageSender(messageSender); + template.setDefaultUri("http://localhost:8888/"); + template.setMessageSender(new HttpUrlConnectionMessageSender()); } protected void tearDown() throws Exception { 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 88bbdf38..9523c743 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 @@ -16,19 +16,16 @@ package org.springframework.ws.client.core; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; import org.custommonkey.xmlunit.XMLTestCase; import org.easymock.MockControl; import org.springframework.oxm.Marshaller; import org.springframework.oxm.Unmarshaller; +import org.springframework.ws.MockWebServiceMessage; import org.springframework.ws.MockWebServiceMessageFactory; import org.springframework.ws.WebServiceMessage; import org.springframework.ws.transport.FaultAwareWebServiceConnection; -import org.springframework.ws.transport.MockTransportInputStream; -import org.springframework.ws.transport.MockTransportOutputStream; import org.springframework.ws.transport.WebServiceConnection; import org.springframework.ws.transport.WebServiceMessageSender; import org.springframework.xml.transform.StringResult; @@ -42,19 +39,29 @@ public class WebServiceTemplateTest extends XMLTestCase { private FaultAwareWebServiceConnection connectionMock; + private MockWebServiceMessageFactory messageFactory; + + private static final String URI = "uri"; + protected void setUp() throws Exception { template = new WebServiceTemplate(); - MockWebServiceMessageFactory messageFactory = new MockWebServiceMessageFactory(); + messageFactory = new MockWebServiceMessageFactory(); template.setMessageFactory(messageFactory); connectionControl = MockControl.createStrictControl(FaultAwareWebServiceConnection.class); connectionMock = (FaultAwareWebServiceConnection) connectionControl.getMock(); template.setMessageSender(new WebServiceMessageSender() { - public WebServiceConnection createConnection() throws IOException { + public WebServiceConnection createConnection(String uri) throws IOException { return connectionMock; } + + public boolean supports(String uri) { + assertEquals("Invalid uri", URI, uri); + return true; + } }); + template.setDefaultUri(URI); } public void testMarshalAndSendNoMarshallerSet() throws Exception { @@ -94,10 +101,10 @@ public class WebServiceTemplateTest extends XMLTestCase { extractorControl.setReturnValue(extracted); extractorControl.replay(); - connectionControl.expectAndReturn(connectionMock.getTransportOutputStream(), - new MockTransportOutputStream(new ByteArrayOutputStream())); - connectionControl.expectAndReturn(connectionMock.getTransportInputStream(), - new MockTransportInputStream(new ByteArrayInputStream("".getBytes("UTF-8")))); + connectionMock.send(null); + connectionControl.setMatcher(MockControl.ALWAYS_MATCHER); + connectionControl + .expectAndReturn(connectionMock.receive(messageFactory), new MockWebServiceMessage("")); connectionControl.expectAndReturn(connectionMock.hasFault(), false); connectionMock.close(); connectionControl.replay(); @@ -122,9 +129,9 @@ public class WebServiceTemplateTest extends XMLTestCase { WebServiceMessageExtractor extractorMock = (WebServiceMessageExtractor) extractorControl.getMock(); extractorControl.replay(); - connectionControl.expectAndReturn(connectionMock.getTransportOutputStream(), - new MockTransportOutputStream(new ByteArrayOutputStream())); - connectionControl.expectAndReturn(connectionMock.getTransportInputStream(), null); + connectionMock.send(null); + connectionControl.setMatcher(MockControl.ALWAYS_MATCHER); + connectionControl.expectAndReturn(connectionMock.receive(messageFactory), null); connectionMock.close(); connectionControl.replay(); @@ -153,10 +160,10 @@ public class WebServiceTemplateTest extends XMLTestCase { faultResolverControl.setMatcher(MockControl.ALWAYS_MATCHER); faultResolverControl.replay(); - connectionControl.expectAndReturn(connectionMock.getTransportOutputStream(), - new MockTransportOutputStream(new ByteArrayOutputStream())); - connectionControl.expectAndReturn(connectionMock.getTransportInputStream(), - new MockTransportInputStream(new ByteArrayInputStream("".getBytes("UTF-8")))); + connectionMock.send(null); + connectionControl.setMatcher(MockControl.ALWAYS_MATCHER); + connectionControl + .expectAndReturn(connectionMock.receive(messageFactory), new MockWebServiceMessage("")); connectionControl.expectAndReturn(connectionMock.hasFault(), true); connectionMock.close(); connectionControl.replay(); @@ -178,10 +185,10 @@ public class WebServiceTemplateTest extends XMLTestCase { extractorControl.setReturnValue(extracted); extractorControl.replay(); - connectionControl.expectAndReturn(connectionMock.getTransportOutputStream(), - new MockTransportOutputStream(new ByteArrayOutputStream())); - connectionControl.expectAndReturn(connectionMock.getTransportInputStream(), - new MockTransportInputStream(new ByteArrayInputStream("".getBytes("UTF-8")))); + connectionMock.send(null); + connectionControl.setMatcher(MockControl.ALWAYS_MATCHER); + connectionControl + .expectAndReturn(connectionMock.receive(messageFactory), new MockWebServiceMessage("")); connectionControl.expectAndReturn(connectionMock.hasFault(), false); connectionMock.close(); connectionControl.replay(); @@ -198,9 +205,9 @@ public class WebServiceTemplateTest extends XMLTestCase { SourceExtractor extractorMock = (SourceExtractor) extractorControl.getMock(); extractorControl.replay(); - connectionControl.expectAndReturn(connectionMock.getTransportOutputStream(), - new MockTransportOutputStream(new ByteArrayOutputStream())); - connectionControl.expectAndReturn(connectionMock.getTransportInputStream(), null); + connectionMock.send(null); + connectionControl.setMatcher(MockControl.ALWAYS_MATCHER); + connectionControl.expectAndReturn(connectionMock.receive(messageFactory), null); connectionMock.close(); connectionControl.replay(); @@ -212,10 +219,10 @@ public class WebServiceTemplateTest extends XMLTestCase { } public void testSendAndReceiveResultResponse() throws Exception { - connectionControl.expectAndReturn(connectionMock.getTransportOutputStream(), - new MockTransportOutputStream(new ByteArrayOutputStream())); - connectionControl.expectAndReturn(connectionMock.getTransportInputStream(), - new MockTransportInputStream(new ByteArrayInputStream("".getBytes("UTF-8")))); + connectionMock.send(null); + connectionControl.setMatcher(MockControl.ALWAYS_MATCHER); + connectionControl + .expectAndReturn(connectionMock.receive(messageFactory), new MockWebServiceMessage("")); connectionControl.expectAndReturn(connectionMock.hasFault(), false); connectionMock.close(); connectionControl.replay(); @@ -243,10 +250,10 @@ public class WebServiceTemplateTest extends XMLTestCase { unmarshallerControl.setReturnValue(unmarshalled); unmarshallerControl.replay(); - connectionControl.expectAndReturn(connectionMock.getTransportOutputStream(), - new MockTransportOutputStream(new ByteArrayOutputStream())); - connectionControl.expectAndReturn(connectionMock.getTransportInputStream(), - new MockTransportInputStream(new ByteArrayInputStream("".getBytes("UTF-8")))); + connectionMock.send(null); + connectionControl.setMatcher(MockControl.ALWAYS_MATCHER); + connectionControl + .expectAndReturn(connectionMock.receive(messageFactory), new MockWebServiceMessage("")); connectionControl.expectAndReturn(connectionMock.hasFault(), false); connectionMock.close(); connectionControl.replay(); @@ -272,9 +279,10 @@ public class WebServiceTemplateTest extends XMLTestCase { template.setUnmarshaller(unmarshallerMock); unmarshallerControl.replay(); - connectionControl.expectAndReturn(connectionMock.getTransportOutputStream(), - new MockTransportOutputStream(new ByteArrayOutputStream())); - connectionControl.expectAndReturn(connectionMock.getTransportInputStream(), null); + connectionMock.send(null); + connectionControl.setMatcher(MockControl.ALWAYS_MATCHER); + connectionControl + .expectAndReturn(connectionMock.receive(messageFactory), null); connectionMock.close(); connectionControl.replay(); @@ -286,4 +294,49 @@ public class WebServiceTemplateTest extends XMLTestCase { unmarshallerControl.verify(); } + public void testSendAndReceiveCustomUri() throws Exception { + final String customUri = "customUri"; + template.setMessageSender(new WebServiceMessageSender() { + + public WebServiceConnection createConnection(String uri) throws IOException { + return connectionMock; + } + + public boolean supports(String uri) { + assertEquals("Invalid uri", customUri, uri); + return true; + } + }); + 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(); + extractorMock.extractData(null); + extractorControl.setMatcher(MockControl.ALWAYS_MATCHER); + Object extracted = new Object(); + extractorControl.setReturnValue(extracted); + extractorControl.replay(); + + connectionMock.send(null); + connectionControl.setMatcher(MockControl.ALWAYS_MATCHER); + connectionControl + .expectAndReturn(connectionMock.receive(messageFactory), new MockWebServiceMessage("")); + connectionControl.expectAndReturn(connectionMock.hasFault(), false); + connectionMock.close(); + connectionControl.replay(); + + Object result = template.sendAndReceive(customUri, requestCallback, extractorMock); + assertEquals("Invalid response", extracted, result); + + callbackControl.verify(); + extractorControl.verify(); + connectionControl.verify(); + + } + + } \ No newline at end of file diff --git a/core/src/test/java/org/springframework/ws/client/support/WebServiceAccessorTest.java b/core/src/test/java/org/springframework/ws/client/support/WebServiceAccessorTest.java deleted file mode 100644 index 05cef1a1..00000000 --- a/core/src/test/java/org/springframework/ws/client/support/WebServiceAccessorTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.client.support; - -import junit.framework.TestCase; -import org.easymock.MockControl; -import org.springframework.ws.WebServiceMessage; -import org.springframework.ws.WebServiceMessageFactory; -import org.springframework.ws.context.MessageContext; -import org.springframework.ws.transport.WebServiceMessageSender; - -public class WebServiceAccessorTest extends TestCase { - - private WebServiceAccessor accessor; - - protected void setUp() throws Exception { - accessor = new MyWebServiceAccessor(); - } - - public void testCreateMessageContext() throws Exception { - MockControl senderControl = MockControl.createControl(WebServiceMessageSender.class); - WebServiceMessageSender senderMock = (WebServiceMessageSender) senderControl.getMock(); - accessor.setMessageSender(senderMock); - MockControl factoryControl = MockControl.createControl(WebServiceMessageFactory.class); - WebServiceMessageFactory factoryMock = (WebServiceMessageFactory) factoryControl.getMock(); - accessor.setMessageFactory(factoryMock); - MockControl messageControl = MockControl.createControl(WebServiceMessage.class); - WebServiceMessage messageMock = (WebServiceMessage) messageControl.getMock(); - accessor.afterPropertiesSet(); - - factoryControl.expectAndReturn(factoryMock.createWebServiceMessage(), messageMock); - - factoryControl.replay(); - messageControl.replay(); - MessageContext messageContext = accessor.createMessageContext(); - assertNotNull("No MessageContext created", messageContext); - factoryControl.verify(); - messageControl.verify(); - } - - private static class MyWebServiceAccessor extends WebServiceAccessor { - - } -} \ No newline at end of file diff --git a/core/src/test/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSenderIntegrationTestCase.java b/core/src/test/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSenderIntegrationTestCase.java index 9d5a511c..7116df8f 100644 --- a/core/src/test/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSenderIntegrationTestCase.java +++ b/core/src/test/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSenderIntegrationTestCase.java @@ -17,14 +17,22 @@ package org.springframework.ws.transport.http; import java.io.IOException; -import java.net.URL; -import java.util.Iterator; +import java.io.OutputStream; import java.util.zip.GZIPOutputStream; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.xml.soap.MessageFactory; +import javax.xml.soap.MimeHeaders; +import javax.xml.soap.SOAPConstants; +import javax.xml.soap.SOAPException; +import javax.xml.soap.SOAPMessage; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; import org.custommonkey.xmlunit.XMLTestCase; import org.custommonkey.xmlunit.XMLUnit; @@ -32,14 +40,18 @@ import org.mortbay.jetty.Server; import org.mortbay.jetty.servlet.Context; import org.mortbay.jetty.servlet.ServletHolder; import org.springframework.util.FileCopyUtils; +import org.springframework.ws.WebServiceMessage; +import org.springframework.ws.WebServiceMessageFactory; +import org.springframework.ws.soap.saaj.SaajSoapMessage; +import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; import org.springframework.ws.transport.FaultAwareWebServiceConnection; -import org.springframework.ws.transport.TransportInputStream; -import org.springframework.ws.transport.TransportOutputStream; import org.springframework.ws.transport.WebServiceConnection; +import org.springframework.xml.transform.StringResult; +import org.springframework.xml.transform.StringSource; public abstract class AbstractHttpWebServiceMessageSenderIntegrationTestCase extends XMLTestCase { - protected Server jettyServer; + private Server jettyServer; private static final String REQUEST_HEADER_NAME = "RequestHeader"; @@ -49,20 +61,38 @@ public abstract class AbstractHttpWebServiceMessageSenderIntegrationTestCase ext private static final String RESPONSE_HEADER_VALUE = "ResponseHeaderValue"; - protected static final String REQUEST = "Request"; + private static final String REQUEST = ""; - protected static final String RESPONSE = "Response"; + private static final String SOAP_REQUEST = + "" + + REQUEST + ""; - protected AbstractHttpWebServiceMessageSender messageSender; + private static final String RESPONSE = ""; + + private static final String SOAP_RESPONSE = + "" + + RESPONSE + ""; + + private AbstractHttpWebServiceMessageSender messageSender; private Context jettyContext; + private static final String URI = "http://localhost:8888/"; + + private MessageFactory saajMessageFactory; + + private TransformerFactory transformerFactory; + + private WebServiceMessageFactory messageFactory; + protected final void setUp() throws Exception { jettyServer = new Server(8888); jettyContext = new Context(jettyServer, "/"); messageSender = createMessageSender(); - messageSender.setUrl(new URL("http://localhost:8888/")); XMLUnit.setIgnoreWhitespace(true); + saajMessageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL); + messageFactory = new SaajSoapMessageFactory(saajMessageFactory); + transformerFactory = TransformerFactory.newInstance(); } protected abstract AbstractHttpWebServiceMessageSender createMessageSender(); @@ -74,39 +104,46 @@ public abstract class AbstractHttpWebServiceMessageSenderIntegrationTestCase ext } public void testSendAndReceiveResponse() throws Exception { - validateResponse(new ResponseServlet()); + MyServlet servlet = new MyServlet(); + servlet.setResponse(true); + validateResponse(servlet); } public void testSendAndReceiveNoResponse() throws Exception { - validateNonResponse(new NoResponseServlet()); + validateNonResponse(new MyServlet()); } public void testSendAndReceiveNoResponseAccepted() throws Exception { - NoResponseServlet servlet = new NoResponseServlet(); + MyServlet servlet = new MyServlet(); servlet.setResponseStatus(HttpServletResponse.SC_ACCEPTED); validateNonResponse(servlet); } public void testSendAndReceiveCompressed() throws Exception { - validateResponse(new CompressedResponseServlet()); + MyServlet servlet = new MyServlet(); + servlet.setResponse(true); + servlet.setGzip(true); + validateResponse(servlet); } public void testSendAndReceiveInvalidContentSize() throws Exception { - validateResponse(new InvalidContentSizeServlet()); + MyServlet servlet = new MyServlet(); + servlet.setResponse(true); + servlet.setContentLength(-1); + validateResponse(servlet); } public void testSendAndReceiveFault() throws Exception { - ResponseServlet servlet = new ResponseServlet(); + MyServlet servlet = new MyServlet(); servlet.setResponseStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); jettyContext.addServlet(new ServletHolder(servlet), "/"); jettyServer.start(); - FaultAwareWebServiceConnection connection = (FaultAwareWebServiceConnection) messageSender.createConnection(); + FaultAwareWebServiceConnection connection = + (FaultAwareWebServiceConnection) messageSender.createConnection(URI); + SOAPMessage request = createRequest(); try { - TransportOutputStream tos = connection.getTransportOutputStream(); - tos.addHeader("Content-Type", "text/xml"); - tos.addHeader(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE); - FileCopyUtils.copy(REQUEST.getBytes("UTF-8"), tos); - assertNotNull("No response", connection.getTransportInputStream()); + connection.send(new SaajSoapMessage(request)); + connection.receive(messageFactory); assertTrue("Response has no fault", connection.hasFault()); } finally { @@ -117,28 +154,23 @@ public abstract class AbstractHttpWebServiceMessageSenderIntegrationTestCase ext private void validateResponse(Servlet servlet) throws Exception { jettyContext.addServlet(new ServletHolder(servlet), "/"); jettyServer.start(); - FaultAwareWebServiceConnection connection = (FaultAwareWebServiceConnection) messageSender.createConnection(); + FaultAwareWebServiceConnection connection = + (FaultAwareWebServiceConnection) messageSender.createConnection(URI); + SOAPMessage request = createRequest(); try { - TransportOutputStream tos = connection.getTransportOutputStream(); - tos.addHeader("Content-Type", "text/xml"); - tos.addHeader(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE); - FileCopyUtils.copy(REQUEST.getBytes("UTF-8"), tos); - assertNotNull("No response", connection.getTransportInputStream()); + connection.send(new SaajSoapMessage(request)); + SaajSoapMessage response = (SaajSoapMessage) connection.receive(messageFactory); + assertNotNull("No response", response); assertFalse("Response has fault", connection.hasFault()); - TransportInputStream tis = connection.getTransportInputStream(); - boolean headerFound = false; - for (Iterator iterator = tis.getHeaderNames(); iterator.hasNext();) { - String headerName = (String) iterator.next(); - if (RESPONSE_HEADER_NAME.equals(headerName)) { - headerFound = true; - } - } - assertTrue("Response has invalid header", headerFound); - Iterator headerValues = tis.getHeaders(RESPONSE_HEADER_NAME); - assertTrue("Response has no header values", headerValues.hasNext()); - assertEquals("Response has invalid header values", RESPONSE_HEADER_VALUE, headerValues.next()); - String result = new String(FileCopyUtils.copyToByteArray(tis), "UTF-8"); - assertEquals("Invalid response", RESPONSE, result); + SOAPMessage saajResponse = response.getSaajMessage(); + String[] headerValues = saajResponse.getMimeHeaders().getHeader(RESPONSE_HEADER_NAME); + assertNotNull("Response has no header", headerValues); + assertEquals("Response has invalid header", 1, headerValues.length); + assertEquals("Response has invalid header values", RESPONSE_HEADER_VALUE, headerValues[0]); + StringResult result = new StringResult(); + Transformer transformer = transformerFactory.newTransformer(); + transformer.transform(response.getPayloadSource(), result); + assertXMLEqual("Invalid response", RESPONSE, result.toString()); } finally { connection.close(); @@ -149,74 +181,90 @@ public abstract class AbstractHttpWebServiceMessageSenderIntegrationTestCase ext jettyContext.addServlet(new ServletHolder(servlet), "/"); jettyServer.start(); - WebServiceConnection connection = messageSender.createConnection(); + WebServiceConnection connection = messageSender.createConnection(URI); + SOAPMessage request = createRequest(); try { - TransportOutputStream tos = connection.getTransportOutputStream(); - tos.addHeader(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE); - FileCopyUtils.copy(REQUEST.getBytes("UTF-8"), tos); - assertNull("Response", connection.getTransportInputStream()); + connection.send(new SaajSoapMessage(request)); + WebServiceMessage response = connection.receive(messageFactory); + assertNull("Response", response); } finally { connection.close(); } } - private static class NoResponseServlet extends HttpServlet { + private SOAPMessage createRequest() throws TransformerException, SOAPException { + SOAPMessage request = saajMessageFactory.createMessage(); + MimeHeaders mimeHeaders = request.getMimeHeaders(); + mimeHeaders.addHeader(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE); + Transformer transformer = transformerFactory.newTransformer(); + transformer.transform(new StringSource(REQUEST), new DOMResult(request.getSOAPBody())); + return request; + } - protected int responseStatus = HttpServletResponse.SC_OK; + private class MyServlet extends HttpServlet { + + private int responseStatus = HttpServletResponse.SC_OK; + + private Integer contentLength; + + private boolean response; + + private boolean gzip; public void setResponseStatus(int responseStatus) { this.responseStatus = responseStatus; } - protected void doPost(HttpServletRequest request, HttpServletResponse response) + public void setContentLength(int contentLength) { + this.contentLength = new Integer(contentLength); + } + + public void setResponse(boolean response) { + this.response = response; + } + + public void setGzip(boolean gzip) { + this.gzip = gzip; + } + + protected void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException { - assertEquals("Invalid header value received on server side", REQUEST_HEADER_VALUE, - request.getHeader(REQUEST_HEADER_NAME)); - String receivedRequest = new String(FileCopyUtils.copyToByteArray(request.getInputStream()), "UTF-8"); - assertEquals("Invalid request received", REQUEST, receivedRequest); + try { + assertEquals("Invalid header value received on server side", REQUEST_HEADER_VALUE, + httpServletRequest.getHeader(REQUEST_HEADER_NAME)); + String receivedRequest = + new String(FileCopyUtils.copyToByteArray(httpServletRequest.getInputStream()), "UTF-8"); + assertXMLEqual("Invalid request received", SOAP_REQUEST, receivedRequest); + if (gzip) { + assertEquals("Invalid Accept-Encoding header value received on server side", "gzip", + httpServletRequest.getHeader("Accept-Encoding")); + } - response.setStatus(responseStatus); - createResponse(request, response); - } - - protected void createResponse(HttpServletRequest request, HttpServletResponse response) throws IOException { + httpServletResponse.setStatus(responseStatus); + if (response) { + httpServletResponse.setContentType("text/xml"); + if (contentLength != null) { + httpServletResponse.setContentLength(contentLength.intValue()); + } + if (gzip) { + httpServletResponse.addHeader("Content-Encoding", "gzip"); + } + httpServletResponse.setHeader(RESPONSE_HEADER_NAME, RESPONSE_HEADER_VALUE); + OutputStream os; + if (gzip) { + os = new GZIPOutputStream(httpServletResponse.getOutputStream()); + } + else { + os = httpServletResponse.getOutputStream(); + } + FileCopyUtils.copy(SOAP_RESPONSE.getBytes("UTF-8"), os); + } + } + catch (Exception ex) { + throw new ServletException(ex); + } } } - private static class ResponseServlet extends NoResponseServlet { - - protected void createResponse(HttpServletRequest request, HttpServletResponse response) throws IOException { - response.setContentType("text/xml"); - response.addHeader(RESPONSE_HEADER_NAME, RESPONSE_HEADER_VALUE); - byte[] buffer = RESPONSE.getBytes("UTF-8"); - response.setContentLength(buffer.length); - FileCopyUtils.copy(buffer, response.getOutputStream()); - } - } - - private static class InvalidContentSizeServlet extends NoResponseServlet { - - protected void createResponse(HttpServletRequest request, HttpServletResponse response) throws IOException { - response.setContentType("text/xml"); - response.addHeader(RESPONSE_HEADER_NAME, RESPONSE_HEADER_VALUE); - response.setContentLength(-1); - byte[] buffer = RESPONSE.getBytes("UTF-8"); - FileCopyUtils.copy(buffer, response.getOutputStream()); - } - } - - private static class CompressedResponseServlet extends NoResponseServlet { - - protected void createResponse(HttpServletRequest request, HttpServletResponse response) throws IOException { - assertEquals("Invalid Accept-Encoding header value received on server side", "gzip", - request.getHeader("Accept-Encoding")); - response.setStatus(HttpServletResponse.SC_OK); - response.setContentType("text/xml"); - response.addHeader(RESPONSE_HEADER_NAME, RESPONSE_HEADER_VALUE); - response.addHeader("Content-Encoding", "gzip"); - byte[] buffer = RESPONSE.getBytes("UTF-8"); - FileCopyUtils.copy(buffer, new GZIPOutputStream(response.getOutputStream())); - } - } } diff --git a/core/src/test/java/org/springframework/ws/transport/http/HttpServletConnectionTest.java b/core/src/test/java/org/springframework/ws/transport/http/HttpServletConnectionTest.java index 2d90c325..81bdede0 100644 --- a/core/src/test/java/org/springframework/ws/transport/http/HttpServletConnectionTest.java +++ b/core/src/test/java/org/springframework/ws/transport/http/HttpServletConnectionTest.java @@ -16,62 +16,83 @@ package org.springframework.ws.transport.http; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; +import javax.xml.soap.MessageFactory; +import javax.xml.soap.MimeHeaders; +import javax.xml.soap.SOAPConstants; +import javax.xml.soap.SOAPMessage; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; -import junit.framework.TestCase; +import org.custommonkey.xmlunit.XMLTestCase; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.util.FileCopyUtils; -import org.springframework.ws.transport.TransportInputStream; +import org.springframework.ws.soap.saaj.SaajSoapMessage; +import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; +import org.springframework.xml.transform.StringResult; +import org.springframework.xml.transform.StringSource; -public class HttpServletConnectionTest extends TestCase { +public class HttpServletConnectionTest extends XMLTestCase { private HttpServletConnection connection; - private MockHttpServletRequest request; + private MockHttpServletRequest httpServletRequest; - private MockHttpServletResponse response; + private MockHttpServletResponse httpServletResponse; + + private static final String HEADER_NAME = "RequestHeader"; + + private static final String HEADER_VALUE = "RequestHeaderValue"; + + private static final String CONTENT = ""; + + private static final String SOAP_CONTENT = + "" + + CONTENT + ""; + + private SaajSoapMessageFactory messageFactory; + + private TransformerFactory transformerFactory; protected void setUp() throws Exception { - request = new MockHttpServletRequest(); - response = new MockHttpServletResponse(); - connection = new HttpServletConnection(request, response); + httpServletRequest = new MockHttpServletRequest(); + httpServletResponse = new MockHttpServletResponse(); + connection = new HttpServletConnection(httpServletRequest, httpServletResponse); + MessageFactory saajMessageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL); + messageFactory = new SaajSoapMessageFactory(saajMessageFactory); + transformerFactory = TransformerFactory.newInstance(); } - public void testReadInputStream() throws Exception { - byte[] content = "content".getBytes("UTF-8"); - request.setContent(content); - byte[] result = FileCopyUtils.copyToByteArray(connection.getTransportInputStream()); - assertTrue("Invalid contents", Arrays.equals(content, result)); + public void testReceive() throws Exception { + byte[] bytes = SOAP_CONTENT.getBytes("UTF-8"); + httpServletRequest.addHeader("Content-Type", "text/xml"); + httpServletRequest.addHeader("Content-Length", new Integer(bytes.length).toString()); + httpServletRequest.addHeader(HEADER_NAME, HEADER_VALUE); + httpServletRequest.setContent(bytes); + SaajSoapMessage message = (SaajSoapMessage) connection.receive(messageFactory); + assertNotNull("No message received", message); + StringResult result = new StringResult(); + Transformer transformer = transformerFactory.newTransformer(); + transformer.transform(message.getPayloadSource(), result); + assertXMLEqual("Invalid message", CONTENT, result.toString()); + SOAPMessage saajMessage = message.getSaajMessage(); + String[] headerValues = saajMessage.getMimeHeaders().getHeader(HEADER_NAME); + assertNotNull("Response has no header", headerValues); + assertEquals("Response has invalid header", 1, headerValues.length); + assertEquals("Response has invalid header values", HEADER_VALUE, headerValues[0]); } - public void testGetHeaders() throws Exception { - String headerName = "Header"; - String headerValue = "Value"; - request.addHeader(headerName, headerValue); - TransportInputStream tis = connection.getTransportInputStream(); - Iterator iterator = tis.getHeaderNames(); - assertTrue("No headers found", iterator.hasNext()); - assertEquals("Invalid header", headerName, iterator.next()); - iterator = tis.getHeaders(headerName); - assertTrue("No header values found", iterator.hasNext()); - assertEquals("Invalid header value", headerValue, iterator.next()); + public void testSend() throws Exception { + SaajSoapMessage message = (SaajSoapMessage) messageFactory.createWebServiceMessage(); + SOAPMessage saajMessage = message.getSaajMessage(); + MimeHeaders mimeHeaders = saajMessage.getMimeHeaders(); + mimeHeaders.addHeader(HEADER_NAME, HEADER_VALUE); + Transformer transformer = transformerFactory.newTransformer(); + transformer.transform(new StringSource(CONTENT), message.getPayloadResult()); + + connection.send(message); + + assertEquals("Invalid header", HEADER_VALUE, httpServletResponse.getHeader(HEADER_NAME)); + assertXMLEqual("Invalid content", SOAP_CONTENT, httpServletResponse.getContentAsString()); } - public void testWriteOutputStream() throws Exception { - byte[] content = "content".getBytes("UTF-8"); - FileCopyUtils.copy(content, connection.getTransportOutputStream()); - assertTrue("Invalid contents", Arrays.equals(content, response.getContentAsByteArray())); - } - - public void testAddHeaders() throws Exception { - String headerName = "Header"; - String headerValue = "Value"; - connection.getTransportOutputStream().addHeader(headerName, headerValue); - assertTrue("No header set", response.getHeaderNames().contains(headerName)); - assertEquals("Invalid header value set", Collections.singletonList(headerValue), - response.getHeaders(headerName)); - } } \ No newline at end of file diff --git a/core/src/test/java/org/springframework/ws/transport/http/WebServiceMessageReceiverHandlerAdapterTest.java b/core/src/test/java/org/springframework/ws/transport/http/WebServiceMessageReceiverHandlerAdapterTest.java index cf1a0bdb..ed3a0356 100644 --- a/core/src/test/java/org/springframework/ws/transport/http/WebServiceMessageReceiverHandlerAdapterTest.java +++ b/core/src/test/java/org/springframework/ws/transport/http/WebServiceMessageReceiverHandlerAdapterTest.java @@ -52,13 +52,10 @@ public class WebServiceMessageReceiverHandlerAdapterTest extends TestCase { private WebServiceMessage requestMock; - private HttpServletConnection connection; - protected void setUp() throws Exception { adapter = new WebServiceMessageReceiverHandlerAdapter(); httpRequest = new MockHttpServletRequest(); httpResponse = new MockHttpServletResponse(); - connection = new HttpServletConnection(httpRequest, httpResponse); factoryControl = MockControl.createControl(WebServiceMessageFactory.class); factoryMock = (WebServiceMessageFactory) factoryControl.getMock(); adapter.setMessageFactory(factoryMock); @@ -86,7 +83,7 @@ public class WebServiceMessageReceiverHandlerAdapterTest extends TestCase { httpRequest.setContent(REQUEST.getBytes("UTF-8")); httpRequest.setContentType("text/xml; charset=\"utf-8\""); httpRequest.setCharacterEncoding("UTF-8"); - factoryMock.createWebServiceMessage(connection.getTransportInputStream()); + factoryMock.createWebServiceMessage(null); factoryControl.setMatcher(MockControl.ALWAYS_MATCHER); factoryControl.setReturnValue(responseMock); @@ -109,12 +106,12 @@ public class WebServiceMessageReceiverHandlerAdapterTest extends TestCase { httpRequest.setContent(REQUEST.getBytes("UTF-8")); httpRequest.setContentType("text/xml; charset=\"utf-8\""); httpRequest.setCharacterEncoding("UTF-8"); - factoryMock.createWebServiceMessage(connection.getTransportInputStream()); + factoryMock.createWebServiceMessage(null); factoryControl.setMatcher(MockControl.ALWAYS_MATCHER); factoryControl.setReturnValue(requestMock); factoryControl.expectAndReturn(factoryMock.createWebServiceMessage(), responseMock); messageControl.expectAndReturn(responseMock.hasFault(), false); - responseMock.writeTo(connection.getTransportOutputStream()); + responseMock.writeTo(null); messageControl.setMatcher(MockControl.ALWAYS_MATCHER); replayMockControls(); @@ -136,12 +133,12 @@ public class WebServiceMessageReceiverHandlerAdapterTest extends TestCase { httpRequest.setContent(REQUEST.getBytes("UTF-8")); httpRequest.setContentType("text/xml; charset=\"utf-8\""); httpRequest.setCharacterEncoding("UTF-8"); - factoryMock.createWebServiceMessage(connection.getTransportInputStream()); + factoryMock.createWebServiceMessage(null); factoryControl.setMatcher(MockControl.ALWAYS_MATCHER); factoryControl.setReturnValue(requestMock); factoryControl.expectAndReturn(factoryMock.createWebServiceMessage(), responseMock); messageControl.expectAndReturn(responseMock.hasFault(), true); - responseMock.writeTo(connection.getTransportOutputStream()); + responseMock.writeTo(null); messageControl.setMatcher(MockControl.ALWAYS_MATCHER); replayMockControls(); @@ -164,7 +161,7 @@ public class WebServiceMessageReceiverHandlerAdapterTest extends TestCase { httpRequest.setContent(REQUEST.getBytes("UTF-8")); httpRequest.setContentType("text/xml; charset=\"utf-8\""); httpRequest.setCharacterEncoding("UTF-8"); - factoryMock.createWebServiceMessage(connection.getTransportInputStream()); + factoryMock.createWebServiceMessage(null); factoryControl.setMatcher(MockControl.ALWAYS_MATCHER); factoryControl.setReturnValue(requestMock); diff --git a/samples/echo/client/spring-ws/src/org/springframework/ws/samples/echo/client/sws/applicationContext.xml b/samples/echo/client/spring-ws/src/org/springframework/ws/samples/echo/client/sws/applicationContext.xml index 8b74bf20..699494da 100644 --- a/samples/echo/client/spring-ws/src/org/springframework/ws/samples/echo/client/sws/applicationContext.xml +++ b/samples/echo/client/spring-ws/src/org/springframework/ws/samples/echo/client/sws/applicationContext.xml @@ -3,19 +3,8 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> - - - - + - - - - - - - - diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 4f62a055..9681835a 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -6,6 +6,7 @@ + Changing URL in CommonsHttpMessageSender Allow SoapFaultMappingExceptionResolver to use strategy to obtain SoapFaultDefinition diff --git a/src/site/apt/upgrading.apt b/src/site/apt/upgrading.apt index b00ff5e8..d491c4be 100644 --- a/src/site/apt/upgrading.apt +++ b/src/site/apt/upgrading.apt @@ -1,25 +1,35 @@ --------- Upgrading --------- + 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 - should help most users the project update their applications: +should help most users the project update their applications: * Attachments - * The <<>> interface was moved from <> to <>. + Attachment support had to be moved and changed to facilitate MTOM. + + * The <<>> interface was moved from <<>> to <<>>. * The <<>> property on <<> was renamed to <>>. * Methods for getting and adding attachments were taken from <<> and extraced into a new interface: - <<>>. Adding a method requires a content id now. +<<>>. Adding a method requires a content id now. * WebServiceTemplate - The <<> no longer declares an IOException for each method. Rather, an runtime exception + The <<>> no longer declares an IOException for each method. Rather, an runtime exception hierarchy has been created in <<>>. +* HttpUrlConnectionMessageSender and CommonsHttpMessageSender + + The <<>> and <<>> have lost their <<>> property. URLs +(or rather: URIs) are now defined on the <<>> by specifying a default URI, or by giving the URI as a +parameter. + + * EndpointInterceptor The <<>> has a <<>> method now, which gets invoked @@ -84,7 +94,7 @@ the project update their applications: * TransportContext - * <<>> and <<>> to <<>> package. + * <<>> and <<>> have been moved to <<>> package. * MessageEndpointAdapter