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 36fcee0e..b4613b58 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
@@ -31,6 +31,9 @@ import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.client.WebServiceClientException;
import org.springframework.ws.client.support.WebServiceAccessor;
import org.springframework.ws.context.MessageContext;
+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.ws.transport.WebServiceMessageSender;
@@ -76,44 +79,32 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
setMessageSender(messageSender);
}
- /**
- * Returns the marshaller for this template.
- */
+ /** Returns the marshaller for this template. */
public Marshaller getMarshaller() {
return marshaller;
}
- /**
- * Sets the marshaller for this template.
- */
+ /** Sets the marshaller for this template. */
public void setMarshaller(Marshaller marshaller) {
this.marshaller = marshaller;
}
- /**
- * Returns the unmarshaller for this template.
- */
+ /** Returns the unmarshaller for this template. */
public Unmarshaller getUnmarshaller() {
return unmarshaller;
}
- /**
- * Sets the unmarshaller for this template.
- */
+ /** Sets the unmarshaller for this template. */
public void setUnmarshaller(Unmarshaller unmarshaller) {
this.unmarshaller = unmarshaller;
}
- /**
- * Returns the fault resolver for this template.
- */
+ /** Returns the fault resolver for this template. */
public FaultResolver getFaultResolver() {
return faultResolver;
}
- /**
- * Sets the fault resolver for this template.
- */
+ /** Sets the fault resolver for this template. */
public void setFaultResolver(FaultResolver faultResolver) {
Assert.notNull(faultResolver, "faultResolver must not be null");
this.faultResolver = faultResolver;
@@ -185,36 +176,6 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
/*
* Source-handling methods
*/
-/*
- public Source sendAndReceive(final Source requestPayload) throws IOException {
- return sendAndReceive(requestPayload, (WebServiceMessageCallback) null);
- }
-*/
-
- /*
- public Source sendAndReceive(final Source requestPayload, final WebServiceMessageCallback requestCallback)
- throws IOException {
- return (Source) sendAndReceive(new WebServiceMessageCallback() {
- public void doInMessage(WebServiceMessage message) throws IOException {
- try {
- Transformer transformer = createTransformer();
- transformer.transform(requestPayload, message.getPayloadResult());
- if (requestCallback != null) {
- requestCallback.doInMessage(message);
- }
- }
- catch (TransformerException ex) {
- throw new WebServiceClientException("Could not transform payload to request message", ex);
- }
- }
- }, new WebServiceMessageExtractor() {
-
- public Object extractData(WebServiceMessage message) throws IOException {
- return message.getPayloadSource();
- }
- });
- }
- */
public Object sendAndReceive(final Source requestPayload, final SourceExtractor responseExtractor)
throws IOException {
@@ -254,8 +215,8 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
}
/*
- * WebServiceMessage-handling methods
- */
+ * WebServiceMessage-handling methods
+ */
public void sendAndReceive(WebServiceMessageCallback requestCallback, WebServiceMessageCallback responseCallback)
throws IOException {
@@ -266,33 +227,64 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
public Object sendAndReceive(WebServiceMessageCallback requestCallback,
WebServiceMessageExtractor responseExtractor) throws IOException {
Assert.notNull(responseExtractor, "response extractor must not be null");
- WebServiceConnection connection = getMessageSender().createConnection();
MessageContext messageContext = createMessageContext();
+ WebServiceConnection connection = getMessageSender().createConnection();
try {
+ WebServiceMessage request = messageContext.getRequest();
if (requestCallback != null) {
- requestCallback.doInMessage(messageContext.getRequest());
+ requestCallback.doInMessage(request);
}
- connection.sendAndReceive(messageContext);
- if (!messageContext.hasResponse()) {
- return null;
- }
- WebServiceMessage response = messageContext.getResponse();
- if (response.hasFault()) {
- getFaultResolver().resolveFault(response);
- return null;
- }
- else {
- return responseExtractor.extractData(response);
+ sendRequest(connection, messageContext);
+ TransportInputStream tis = connection.getTransportInputStream();
+ if (tis != null) {
+ try {
+ messageContext.readResponse(tis);
+ if (messageContext.hasResponse()) {
+ WebServiceMessage response = messageContext.getResponse();
+ if (!hasFault(connection, messageContext)) {
+ // normal response
+ return responseExtractor.extractData(response);
+ }
+ else {
+ // fault response
+ getFaultResolver().resolveFault(response);
+ }
+ }
+ }
+ finally {
+ tis.close();
+ }
}
+ return null;
}
finally {
connection.close();
}
}
- /**
- * Adapter to enable use of a WebServiceMessageCallback inside a WebServiceMessageExtractor.
- */
+ /** Sends the request in the given message context over the connection. */
+ private void sendRequest(WebServiceConnection connection, MessageContext messageContext) throws IOException {
+ TransportOutputStream tos = connection.getTransportOutputStream();
+ try {
+ messageContext.getRequest().writeTo(tos);
+ tos.flush();
+ }
+ finally {
+ tos.close();
+ }
+ }
+
+ /** Determines whether the given connection or message context has a fault. */
+ private boolean hasFault(WebServiceConnection connection, MessageContext messageContext) throws IOException {
+ if (connection instanceof FaultAwareWebServiceConnection) {
+ return ((FaultAwareWebServiceConnection) connection).hasFault();
+ }
+ else {
+ return messageContext.getResponse().hasFault();
+ }
+ }
+
+ /** Adapter to enable use of a WebServiceMessageCallback inside a WebServiceMessageExtractor. */
private static class WebServiceMessageCallbackMessageExtractor implements WebServiceMessageExtractor {
private final WebServiceMessageCallback callback;
@@ -307,9 +299,7 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService
}
}
- /**
- * Adapter to enable use of a SourceExtractor inside a WebServiceMessageExtractor.
- */
+ /** Adapter to enable use of a SourceExtractor inside a WebServiceMessageExtractor. */
private static class SourceExtractorMessageExtractor implements WebServiceMessageExtractor {
private final SourceExtractor sourceExtractor;
diff --git a/core/src/main/java/org/springframework/ws/transport/FaultAwareWebServiceConnection.java b/core/src/main/java/org/springframework/ws/transport/FaultAwareWebServiceConnection.java
new file mode 100644
index 00000000..620f2d7c
--- /dev/null
+++ b/core/src/main/java/org/springframework/ws/transport/FaultAwareWebServiceConnection.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+/**
+ * Sub-interface of {@link WebServiceConnection} that is aware of any Faults received. Typically, fault detection is
+ * done by inspecting connection error codes, etc.
+ *
+ * @author Arjen Poutsma
+ */
+public interface FaultAwareWebServiceConnection extends WebServiceConnection {
+
+ /**
+ * Indicates whether this connection has a fault.
+ *
+ * @return true if this connection has a fault; false otherwise.
+ */
+ boolean hasFault() throws IOException;
+
+}
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 acc42a0a..12b8baca 100644
--- a/core/src/main/java/org/springframework/ws/transport/WebServiceConnection.java
+++ b/core/src/main/java/org/springframework/ws/transport/WebServiceConnection.java
@@ -19,33 +19,59 @@ package org.springframework.ws.transport;
import java.io.IOException;
import org.springframework.ws.WebServiceMessage;
-import org.springframework.ws.context.MessageContext;
+import org.springframework.ws.transport.http.HttpServletConnection;
/**
* Represents a point-to-point connection that a client can use for sending {@link WebServiceMessage} objects directly
* to a remote party.
*
WebServiceConnection can be obtained using a {@link WebServiceMessageSender}.
+ *
+ * On the receiving side, the typical usage scenario for this connection is: null if no transport input stream is available (eg. a request might not have a response).
*
- * @param messageContext the context which contains the request message to be sent, and which will contain the
- * response afterwards
- * @throws IOException in case of I/O errors
+ * @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
*/
- void sendAndReceive(MessageContext messageContext) throws IOException;
+ TransportInputStream getTransportInputStream() throws IOException;
/**
- * Closes the WebServiceConnection.
+ * 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).
*
- * @throws IOException in case of I/O errors
+ * @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
+ */
+ TransportOutputStream getTransportOutputStream() 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
*/
void close() throws IOException;
diff --git a/core/src/main/java/org/springframework/ws/transport/context/DefaultTransportContext.java b/core/src/main/java/org/springframework/ws/transport/context/DefaultTransportContext.java
index e84387ca..48d70ca4 100644
--- a/core/src/main/java/org/springframework/ws/transport/context/DefaultTransportContext.java
+++ b/core/src/main/java/org/springframework/ws/transport/context/DefaultTransportContext.java
@@ -16,8 +16,7 @@
package org.springframework.ws.transport.context;
-import org.springframework.ws.transport.TransportInputStream;
-import org.springframework.ws.transport.TransportOutputStream;
+import org.springframework.ws.transport.WebServiceConnection;
/**
* Default implementation of the TransportContext interface.
@@ -26,24 +25,15 @@ import org.springframework.ws.transport.TransportOutputStream;
*/
public class DefaultTransportContext implements TransportContext {
- private final TransportInputStream transportInputStream;
+ private final WebServiceConnection connection;
- private final TransportOutputStream transportOutputStream;
-
- /**
- * Creates a new DefaultTransportContext that exposes the given streams.
- */
- public DefaultTransportContext(TransportInputStream transportInputStream,
- TransportOutputStream transportOutputStream) {
- this.transportInputStream = transportInputStream;
- this.transportOutputStream = transportOutputStream;
+ /** Creates a new DefaultTransportContext that exposes the given connection. */
+ public DefaultTransportContext(WebServiceConnection connection) {
+ this.connection = connection;
}
- public TransportInputStream getTransportInputStream() {
- return transportInputStream;
+ public WebServiceConnection getConnection() {
+ return connection;
}
- public TransportOutputStream getTransportOutputStream() {
- return transportOutputStream;
- }
}
diff --git a/core/src/main/java/org/springframework/ws/transport/context/TransportContext.java b/core/src/main/java/org/springframework/ws/transport/context/TransportContext.java
index a7a06997..3094455f 100644
--- a/core/src/main/java/org/springframework/ws/transport/context/TransportContext.java
+++ b/core/src/main/java/org/springframework/ws/transport/context/TransportContext.java
@@ -1,11 +1,9 @@
package org.springframework.ws.transport.context;
-import org.springframework.ws.transport.TransportInputStream;
-import org.springframework.ws.transport.TransportOutputStream;
+import org.springframework.ws.transport.WebServiceConnection;
/**
- * Strategy interface for determining the current {@link org.springframework.ws.transport.TransportInputStream} and
- * {@link org.springframework.ws.transport.TransportOutputStream}.
+ * Strategy interface for determining the current {@link org.springframework.ws.transport.WebServiceConnection}.
*
* An instance of this class can be associated with a thread via the {@link TransportContextHolder} class.
*
@@ -13,13 +11,6 @@ import org.springframework.ws.transport.TransportOutputStream;
*/
public interface TransportContext {
- /**
- * Returns the current TransportInputStream.
- */
- TransportInputStream getTransportInputStream();
-
- /**
- * Returns the current TransportOutputStream.
- */
- TransportOutputStream getTransportOutputStream();
+ /** Returns the current WebServiceConnection. */
+ WebServiceConnection getConnection();
}
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
new file mode 100644
index 00000000..2e7d7e31
--- /dev/null
+++ b/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpConnection.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.ws.transport.http;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpMethod;
+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.util.FileCopyUtils;
+import org.springframework.ws.transport.FaultAwareWebServiceConnection;
+import org.springframework.ws.transport.TransportInputStream;
+import org.springframework.ws.transport.TransportOutputStream;
+import org.springframework.ws.transport.WebServiceConnection;
+
+/**
+ * Implementation of {@link WebServiceConnection} that is based on Jakarta Commons HttpClient. Exposes a {@link
+ * PostMethod}.
+ *
+ * @author Arjen Poutsma
+ */
+public class CommonsHttpConnection implements FaultAwareWebServiceConnection {
+
+ private final HttpClient httpClient;
+
+ private final PostMethod postMethod;
+
+ private byte[] bufferedInput;
+
+ public CommonsHttpConnection(HttpClient httpClient, PostMethod postMethod) {
+ Assert.notNull(httpClient, "httpClient must not be null");
+ Assert.notNull(postMethod, "postMethod must not be null");
+ this.httpClient = httpClient;
+ this.postMethod = postMethod;
+ }
+
+ /** Returns the wrapped PostMethod. */
+ public HttpMethod getPostMethod() {
+ return postMethod;
+ }
+
+ public void close() throws IOException {
+ postMethod.releaseConnection();
+ }
+
+ public TransportOutputStream getTransportOutputStream() {
+ return new CommonsHttpTransportOutputStream();
+ }
+
+ public TransportInputStream getTransportInputStream() throws IOException {
+ return getContentLength() > 0 ? new CommonsHttpTransportInputStream() : null;
+ }
+
+ public boolean hasFault() throws IOException {
+ return postMethod.getStatusCode() == HttpStatus.SC_INTERNAL_SERVER_ERROR;
+ }
+
+ private long getContentLength() throws IOException {
+ if (postMethod.getResponseContentLength() != -1) {
+ return postMethod.getResponseContentLength();
+ }
+ else if (bufferedInput != null) {
+ return bufferedInput.length;
+ }
+ else {
+ bufferedInput = FileCopyUtils.copyToByteArray(getInputStream());
+ return bufferedInput.length;
+ }
+ }
+
+ private InputStream getInputStream() throws IOException {
+ if (postMethod.getStatusCode() != HttpStatus.SC_INTERNAL_SERVER_ERROR &&
+ postMethod.getStatusCode() / 100 != 2) {
+ throw new HttpTransportException("Did not receive successful HTTP response: status code = " +
+ postMethod.getStatusCode() + ", status message = [" + postMethod.getStatusText() + "]");
+ }
+ return postMethod.getResponseBodyAsStream();
+ }
+
+ /**
+ * Implementation of {@link TransportInputStream} based on the {@link PostMethod} field.
+ *
+ * @see CommonsHttpConnection#postMethod
+ */
+ class CommonsHttpTransportInputStream extends TransportInputStream {
+
+ protected InputStream createInputStream() throws IOException {
+ if (bufferedInput != null) {
+ return new ByteArrayInputStream(bufferedInput);
+ }
+ else {
+ return getInputStream();
+ }
+ }
+
+ public Iterator getHeaderNames() throws IOException {
+ Header[] headers = postMethod.getResponseHeaders();
+ String[] names = new String[headers.length];
+ for (int i = 0; i < headers.length; i++) {
+ names[i] = headers[i].getName();
+ }
+ return Arrays.asList(names).iterator();
+ }
+
+ public Iterator getHeaders(String name) throws IOException {
+ Header[] headers = postMethod.getResponseHeaders(name);
+ String[] values = new String[headers.length];
+ for (int i = 0; i < headers.length; i++) {
+ values[i] = headers[i].getValue();
+ }
+ return Arrays.asList(values).iterator();
+ }
+ }
+
+ /**
+ * Implementation of {@link TransportOutputStream} based on the {@link PostMethod} field.
+ *
+ * @see CommonsHttpConnection#postMethod
+ */
+ class CommonsHttpTransportOutputStream extends TransportOutputStream {
+
+ private final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ public void addHeader(String name, String value) throws IOException {
+ postMethod.addRequestHeader(name, value);
+ }
+
+ protected OutputStream createOutputStream() throws IOException {
+ return bos;
+ }
+
+ public void close() throws IOException {
+ super.close();
+ postMethod.setRequestEntity(new ByteArrayRequestEntity(bos.toByteArray()));
+ 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 a54e8e68..1869f259 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
@@ -19,8 +19,10 @@ package org.springframework.ws.transport.http;
import java.io.IOException;
import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.PostMethod;
+import org.springframework.beans.factory.DisposableBean;
import org.springframework.util.Assert;
import org.springframework.ws.transport.WebServiceConnection;
@@ -34,7 +36,7 @@ import org.springframework.ws.transport.WebServiceConnection;
* @author Arjen Poutsma
* @see org.springframework.ws.transport.http.HttpUrlConnectionMessageSender
*/
-public class CommonsHttpMessageSender extends AbstractHttpWebServiceMessageSender {
+public class CommonsHttpMessageSender extends AbstractHttpWebServiceMessageSender implements DisposableBean {
private HttpClient httpClient;
@@ -60,23 +62,26 @@ public class CommonsHttpMessageSender extends AbstractHttpWebServiceMessageSende
this.httpClient = httpClient;
}
- /**
- * Returns the HttpClient used by this message sender.
- */
+ public void destroy() throws Exception {
+ HttpConnectionManager connectionManager = httpClient.getHttpConnectionManager();
+ if (connectionManager instanceof MultiThreadedHttpConnectionManager) {
+ ((MultiThreadedHttpConnectionManager) connectionManager).shutdown();
+ }
+ }
+
+ /** Returns the HttpClient used by this message sender. */
public HttpClient getHttpClient() {
return httpClient;
}
- /**
- * Set the HttpClient used by this message sender.
- */
+ /** Set the HttpClient used by this message sender. */
public void setHttpClient(HttpClient httpClient) {
this.httpClient = httpClient;
}
public WebServiceConnection createConnection() throws IOException {
PostMethod method = new PostMethod(getUrl().toString());
- return new CommonsHttpWebServiceConnection(getHttpClient(), method);
+ return new CommonsHttpConnection(getHttpClient(), method);
}
}
diff --git a/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpTransportInputStream.java b/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpTransportInputStream.java
deleted file mode 100644
index 42df4601..00000000
--- a/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpTransportInputStream.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2006 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.ws.transport.http;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.Iterator;
-
-import org.apache.commons.httpclient.Header;
-import org.apache.commons.httpclient.HttpMethod;
-import org.apache.commons.httpclient.methods.PostMethod;
-import org.springframework.util.Assert;
-import org.springframework.ws.transport.TransportInputStream;
-
-/**
- * Implementation of the TransportInputStream interface based on {@link
- * org.apache.commons.httpclient.methods.PostMethod}. Exposes the PostMethod.
- *
- * @author Arjen Poutsma
- */
-class CommonsHttpTransportInputStream extends TransportInputStream {
-
- private final PostMethod postMethod;
-
- /**
- * Constructs a new instance of the CommonsHttpTransportInputStream with a given
- * PostMethod.
- */
- public CommonsHttpTransportInputStream(PostMethod postMethod) {
- Assert.notNull(postMethod, "postMethod must not be null");
- this.postMethod = postMethod;
- }
-
- protected InputStream createInputStream() throws IOException {
- return postMethod.getResponseBodyAsStream();
- }
-
- public Iterator getHeaderNames() throws IOException {
- Header[] headers = postMethod.getResponseHeaders();
- String[] names = new String[headers.length];
- for (int i = 0; i < headers.length; i++) {
- names[i] = headers[i].getName();
- }
- return Arrays.asList(names).iterator();
- }
-
- public Iterator getHeaders(String name) throws IOException {
- Header[] headers = postMethod.getResponseHeaders(name);
- String[] names = new String[headers.length];
- for (int i = 0; i < headers.length; i++) {
- names[i] = headers[i].getValue();
- }
- return Arrays.asList(names).iterator();
- }
-
- /**
- * Returns the wrapped PostMethod.
- */
- public HttpMethod getPostMethod() {
- return postMethod;
- }
-}
diff --git a/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpTransportOutputStream.java b/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpTransportOutputStream.java
deleted file mode 100644
index 71834bc1..00000000
--- a/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpTransportOutputStream.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2006 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.ws.transport.http;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.apache.commons.httpclient.HttpMethod;
-import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
-import org.apache.commons.httpclient.methods.PostMethod;
-import org.springframework.ws.transport.TransportOutputStream;
-
-/**
- * Implementation of the TransportOutputStream interface based on {@link
- * org.apache.commons.httpclient.methods.PostMethod}. Exposes the PostMethod.
- *
- * @author Arjen Poutsma
- */
-class CommonsHttpTransportOutputStream extends TransportOutputStream {
-
- private final PostMethod postMethod;
-
- private final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-
- /**
- * Constructs a new instance of the CommonsHttpTransportOutputStream with a given
- * PostMethod.
- */
- public CommonsHttpTransportOutputStream(PostMethod postMethod) {
- this.postMethod = postMethod;
- }
-
- public void addHeader(String name, String value) throws IOException {
- postMethod.addRequestHeader(name, value);
- }
-
- public void close() throws IOException {
- postMethod.setRequestEntity(new ByteArrayRequestEntity(bos.toByteArray()));
- }
-
- protected OutputStream createOutputStream() throws IOException {
- return bos;
- }
-
- /**
- * Returns the wrapped PostMethod.
- */
- public HttpMethod getPostMethod() {
- return postMethod;
- }
-
-}
diff --git a/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpWebServiceConnection.java b/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpWebServiceConnection.java
deleted file mode 100644
index 3f105b36..00000000
--- a/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpWebServiceConnection.java
+++ /dev/null
@@ -1,86 +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.transport.http;
-
-import java.io.IOException;
-
-import org.apache.commons.httpclient.HttpClient;
-import org.apache.commons.httpclient.HttpStatus;
-import org.apache.commons.httpclient.methods.PostMethod;
-import org.springframework.util.Assert;
-import org.springframework.ws.WebServiceMessage;
-import org.springframework.ws.context.MessageContext;
-import org.springframework.ws.transport.WebServiceConnection;
-
-/**
- * Implementation of the {@link WebServiceConnection} that uses Jakarta Commons HttpClient.
- *
- * @author Arjen Poutsma
- */
-public class CommonsHttpWebServiceConnection implements WebServiceConnection {
-
- private final HttpClient httpClient;
-
- private final PostMethod postMethod;
-
- public CommonsHttpWebServiceConnection(HttpClient httpClient, PostMethod postMethod) {
- Assert.notNull(httpClient, "httpClient must not be null");
- Assert.notNull(postMethod, "postMethod must not be null");
- this.httpClient = httpClient;
- this.postMethod = postMethod;
- }
-
- public void close() throws IOException {
- postMethod.releaseConnection();
- }
-
- public void sendAndReceive(MessageContext messageContext) throws IOException {
- writeRequestMessage(messageContext.getRequest());
- executePostMethod();
- validateResponse(postMethod);
- readResponse(postMethod, messageContext);
- }
-
- private void writeRequestMessage(WebServiceMessage message) throws IOException {
- CommonsHttpTransportOutputStream tos = new CommonsHttpTransportOutputStream(postMethod);
- message.writeTo(tos);
- tos.flush();
- // calling close() causes the RequestEntity to be set on the PostMethod
- tos.close();
- }
-
- private void executePostMethod() throws IOException {
- httpClient.executeMethod(postMethod);
- }
-
- private void validateResponse(PostMethod postMethod) throws IOException {
- int statusCode = postMethod.getStatusCode();
- if (statusCode != HttpStatus.SC_INTERNAL_SERVER_ERROR && statusCode / 100 != 2) {
- throw new HttpTransportException("Did not receive successful HTTP response: status code = " + statusCode +
- ", status message = [" + postMethod.getStatusText() + "]");
- }
-
- }
-
- private void readResponse(PostMethod postMethod, MessageContext messageContext) throws IOException {
- if (postMethod.getStatusCode() == HttpStatus.SC_NO_CONTENT || postMethod.getResponseContentLength() == 0) {
- return;
- }
- messageContext.readResponse(new CommonsHttpTransportInputStream(postMethod));
- }
-
-}
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
new file mode 100644
index 00000000..59df649f
--- /dev/null
+++ b/core/src/main/java/org/springframework/ws/transport/http/HttpServletConnection.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.ws.transport.http;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Iterator;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.ws.transport.TransportInputStream;
+import org.springframework.ws.transport.TransportOutputStream;
+import org.springframework.ws.transport.WebServiceConnection;
+import org.springframework.ws.transport.support.EnumerationIterator;
+
+/**
+ * Implementation of {@link WebServiceConnection} that is based on the Servlet API. Exposes a {@link HttpServletRequest}
+ * and {@link HttpServletResponse}.
+ *
+ * @author Arjen Poutsma
+ * @author Arjen Poutsma
+ * @see #getHttpServletRequest()
+ * @see #getHttpServletResponse()
+ */
+public class HttpServletConnection implements WebServiceConnection {
+
+ private final HttpServletRequest httpServletRequest;
+
+ private final HttpServletResponse httpServletResponse;
+
+ /**
+ * Constructs a new servlet connection with the given HttpServletRequest and
+ * HttpServletResponse.
+ */
+ public HttpServletConnection(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
+ this.httpServletRequest = httpServletRequest;
+ this.httpServletResponse = httpServletResponse;
+ }
+
+ /** Returns the HttpServletRequest for this connection. */
+ public HttpServletRequest getHttpServletRequest() {
+ return httpServletRequest;
+ }
+
+ /** Returns the HttpServletResponse for this connection. */
+ public HttpServletResponse getHttpServletResponse() {
+ return httpServletResponse;
+ }
+
+ public TransportInputStream getTransportInputStream() {
+ return new HttpServletTransportInputStream();
+ }
+
+ public TransportOutputStream getTransportOutputStream() {
+ return new HttpServletTransportOutputStream();
+ }
+
+ public void close() throws IOException {
+ // no op
+ }
+
+ /**
+ * Implementation of {@link TransportInputStream} based on the {@link HttpServletRequest} field.
+ *
+ * @see HttpServletConnection#httpServletRequest
+ */
+ private class HttpServletTransportInputStream extends TransportInputStream {
+
+ protected InputStream createInputStream() throws IOException {
+ return httpServletRequest.getInputStream();
+ }
+
+ public Iterator getHeaderNames() {
+ return new EnumerationIterator(httpServletRequest.getHeaderNames());
+ }
+
+ public Iterator getHeaders(String name) {
+ return new EnumerationIterator(httpServletRequest.getHeaders(name));
+ }
+ }
+
+ /**
+ * Implementation of {@link TransportOutputStream} based on the {@link HttpServletResponse} field.
+ *
+ * @see HttpServletConnection#httpServletResponse
+ */
+ private class HttpServletTransportOutputStream extends TransportOutputStream {
+
+ protected OutputStream createOutputStream() throws IOException {
+ return httpServletResponse.getOutputStream();
+ }
+
+ public void addHeader(String name, String value) {
+ httpServletResponse.addHeader(name, value);
+ }
+ }
+
+
+}
diff --git a/core/src/main/java/org/springframework/ws/transport/http/HttpServletTransportInputStream.java b/core/src/main/java/org/springframework/ws/transport/http/HttpServletTransportInputStream.java
deleted file mode 100644
index c17d9886..00000000
--- a/core/src/main/java/org/springframework/ws/transport/http/HttpServletTransportInputStream.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2006 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.ws.transport.http;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Iterator;
-import javax.servlet.http.HttpServletRequest;
-
-import org.springframework.ws.transport.TransportInputStream;
-import org.springframework.ws.transport.support.EnumerationIterator;
-
-/**
- * HTTP Servlet specific implementation of the TransportInputStream interface. Exposes the
- * HttpServletRequest.
- *
- * @author Arjen Poutsma
- * @see #getHttpServletRequest()
- */
-class HttpServletTransportInputStream extends TransportInputStream {
-
- private final HttpServletRequest httpServletRequest;
-
- /**
- * Constructs a new instance of the HttpTransportRequest with the given
- * HttpServletRequest.
- */
- public HttpServletTransportInputStream(HttpServletRequest httpServletRequest) throws IOException {
- this.httpServletRequest = httpServletRequest;
- }
-
- protected InputStream createInputStream() throws IOException {
- return httpServletRequest.getInputStream();
- }
-
- /**
- * Returns the wrapped HttpServletRequest.
- */
- public HttpServletRequest getHttpServletRequest() {
- return httpServletRequest;
- }
-
- public Iterator getHeaderNames() {
- return new EnumerationIterator(httpServletRequest.getHeaderNames());
- }
-
- public Iterator getHeaders(String name) {
- return new EnumerationIterator(httpServletRequest.getHeaders(name));
- }
-}
diff --git a/core/src/main/java/org/springframework/ws/transport/http/HttpServletTransportOutputStream.java b/core/src/main/java/org/springframework/ws/transport/http/HttpServletTransportOutputStream.java
deleted file mode 100644
index 7f4996e8..00000000
--- a/core/src/main/java/org/springframework/ws/transport/http/HttpServletTransportOutputStream.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2006 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.ws.transport.http;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import javax.servlet.http.HttpServletResponse;
-
-import org.springframework.ws.transport.TransportOutputStream;
-
-/**
- * HTTP Servlet specific implementation of the TransportOutputStream interface. Exposes the
- * HttpServletResponse.
- *
- * @author Arjen Poutsma
- * @see #getHttpServletResponse()
- */
-class HttpServletTransportOutputStream extends TransportOutputStream {
-
- private final HttpServletResponse httpServletResponse;
-
- /**
- * Constructs a new instance of the HttpTransportResponse with the given
- * HttpServletResponse.
- */
- public HttpServletTransportOutputStream(HttpServletResponse httpServletResponse) throws IOException {
- this.httpServletResponse = httpServletResponse;
- }
-
- protected OutputStream createOutputStream() throws IOException {
- return httpServletResponse.getOutputStream();
- }
-
- /**
- * Returns the wrapped HttpServletResponse.
- */
- public HttpServletResponse getHttpServletResponse() {
- return httpServletResponse;
- }
-
- public void addHeader(String name, String value) {
- httpServletResponse.addHeader(name, value);
- }
-}
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
new file mode 100644
index 00000000..4213d168
--- /dev/null
+++ b/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnection.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.ws.transport.http;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.ProtocolException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.util.Assert;
+import org.springframework.util.FileCopyUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.ws.transport.FaultAwareWebServiceConnection;
+import org.springframework.ws.transport.TransportInputStream;
+import org.springframework.ws.transport.TransportOutputStream;
+import org.springframework.ws.transport.WebServiceConnection;
+
+/**
+ * Implementation of the {@link WebServiceConnection} interface that uses a {@link HttpURLConnection}.
+ *
+ * @author Arjen Poutsma
+ */
+public class HttpUrlConnection implements FaultAwareWebServiceConnection {
+
+ private final HttpURLConnection connection;
+
+ private byte[] bufferedInput;
+
+ /** Creates a new instance of the HttpUrlConnection with the given HttpURLConnection. */
+ public HttpUrlConnection(HttpURLConnection connection) throws ProtocolException {
+ Assert.notNull(connection, "connection must not be null");
+ this.connection = connection;
+ }
+
+ /** Returns the wrapped HttpURLConnection. */
+ public HttpURLConnection getConnection() {
+ return connection;
+ }
+
+ public void close() {
+ connection.disconnect();
+ }
+
+ public TransportOutputStream getTransportOutputStream() {
+ return new HttpUrlConnectionTransportOutputStream();
+ }
+
+ public TransportInputStream getTransportInputStream() throws IOException {
+ return getContentLength() > 0 ? new HttpUrlConnectionTransportInputStream() : null;
+ }
+
+ public boolean hasFault() throws IOException {
+ return connection.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR;
+ }
+
+ private int getContentLength() throws IOException {
+ if (connection.getContentLength() != -1) {
+ return connection.getContentLength();
+ }
+ else if (bufferedInput != null) {
+ return bufferedInput.length;
+ }
+ else {
+ bufferedInput = FileCopyUtils.copyToByteArray(getInputStream());
+ return bufferedInput.length;
+ }
+ }
+
+ private InputStream getInputStream() throws IOException {
+ if (connection.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR) {
+ return connection.getErrorStream();
+ }
+ else if (connection.getResponseCode() / 100 == 2) {
+ return connection.getInputStream();
+ }
+ else {
+ throw new HttpTransportException("Did not receive successful HTTP response: status code = " +
+ connection.getResponseCode() + ", status message = [" + connection.getResponseMessage() + "]");
+ }
+ }
+
+ /**
+ * Implementation of {@link TransportInputStream} based on the {@link HttpURLConnection} field.
+ *
+ * @see HttpUrlConnection#connection
+ */
+
+ class HttpUrlConnectionTransportInputStream extends TransportInputStream {
+
+ protected InputStream createInputStream() throws IOException {
+ if (bufferedInput != null) {
+ return new ByteArrayInputStream(bufferedInput);
+ }
+ else {
+ return getInputStream();
+ }
+ }
+
+ public Iterator getHeaderNames() throws IOException {
+ List headerNames = new ArrayList();
+ // Header field 0 is the status line, so we start at 1
+ int i = 1;
+ while (true) {
+ String headerName = connection.getHeaderFieldKey(i);
+ if (!StringUtils.hasLength(headerName)) {
+ break;
+ }
+ headerNames.add(headerName);
+ i++;
+ }
+ return headerNames.iterator();
+ }
+
+ public Iterator getHeaders(String name) throws IOException {
+ String headerField = connection.getHeaderField(name);
+ if (headerField == null) {
+ return Collections.EMPTY_LIST.iterator();
+ }
+ else {
+ Set tokens = StringUtils.commaDelimitedListToSet(headerField);
+ return tokens.iterator();
+ }
+ }
+
+ }
+
+ /**
+ * Implementation of {@link TransportOutputStream} based on the {@link HttpURLConnection} field.
+ *
+ * @see HttpUrlConnection#connection
+ */
+ class HttpUrlConnectionTransportOutputStream extends TransportOutputStream {
+
+ public void addHeader(String name, String value) throws IOException {
+ connection.addRequestProperty(name, value);
+ }
+
+ protected OutputStream createOutputStream() throws IOException {
+ return connection.getOutputStream();
+ }
+
+ public void close() throws IOException {
+ super.close();
+ connection.connect();
+ }
+ }
+
+}
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 ef0da86b..e51f4e60 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
@@ -35,12 +35,21 @@ import org.springframework.ws.transport.WebServiceConnection;
*/
public class HttpUrlConnectionMessageSender extends AbstractHttpWebServiceMessageSender {
+ private static final String HTTP_METHOD_POST = "POST";
+
public WebServiceConnection createConnection() throws IOException {
- URLConnection con = getUrl().openConnection();
- if (!(con instanceof HttpURLConnection)) {
+ URLConnection connection = getUrl().openConnection();
+ if (!(connection instanceof HttpURLConnection)) {
throw new HttpTransportException("URL [" + getUrl() + "] is not an HTTP URL");
}
- return new HttpUrlConnectionWebServiceConnection((HttpURLConnection) con);
+ else {
+ HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
+ httpURLConnection.setRequestMethod(HTTP_METHOD_POST);
+ httpURLConnection.setUseCaches(false);
+ httpURLConnection.setDoInput(true);
+ httpURLConnection.setDoOutput(true);
+ return new HttpUrlConnection(httpURLConnection);
+ }
}
}
diff --git a/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionTransportInputStream.java b/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionTransportInputStream.java
deleted file mode 100644
index bc4780d1..00000000
--- a/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionTransportInputStream.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2006 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.ws.transport.http;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-import org.springframework.util.Assert;
-import org.springframework.util.StringUtils;
-import org.springframework.ws.transport.TransportInputStream;
-
-/**
- * Implementation of the TransportInputStream interface based on {@link java.net.HttpURLConnection}.
- * Exposes the HttpURLConnection.
- *
- * @author Arjen Poutsma
- */
-class HttpUrlConnectionTransportInputStream extends TransportInputStream {
-
- private final HttpURLConnection connection;
-
- /**
- * Constructs a new instance of the HttpUrlConnectionTransportInputStream based on the given
- * HttpURLConnection.
- */
- public HttpUrlConnectionTransportInputStream(HttpURLConnection connection) throws IOException {
- Assert.notNull(connection, "connection must not be null");
- this.connection = connection;
- }
-
- protected InputStream createInputStream() throws IOException {
- if (connection.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR) {
- return connection.getErrorStream();
- }
- else {
- return connection.getInputStream();
- }
- }
-
- public Iterator getHeaderNames() throws IOException {
- List headerNames = new ArrayList();
- // Header field 0 is the status line, so we start at 1
- int i = 1;
- while (true) {
- String headerName = connection.getHeaderFieldKey(i);
- if (!StringUtils.hasLength(headerName)) {
- break;
- }
- headerNames.add(headerName);
- i++;
- }
- return headerNames.iterator();
- }
-
- public Iterator getHeaders(String name) throws IOException {
- String headerField = connection.getHeaderField(name);
- if (headerField == null) {
- return Collections.EMPTY_LIST.iterator();
- }
- else {
- Set tokens = StringUtils.commaDelimitedListToSet(headerField);
- return tokens.iterator();
- }
- }
-}
diff --git a/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionTransportOutputStream.java b/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionTransportOutputStream.java
deleted file mode 100644
index 8956c60a..00000000
--- a/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionTransportOutputStream.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2006 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.ws.transport.http;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-
-import org.springframework.util.Assert;
-import org.springframework.ws.transport.TransportOutputStream;
-
-/**
- * Implementation of the TransportOutputStream interface based on {@link java.net.HttpURLConnection}.
- * Exposes the HttpURLConnection.
- *
- * @author Arjen Poutsma
- */
-class HttpUrlConnectionTransportOutputStream extends TransportOutputStream {
-
- private final HttpURLConnection connection;
-
- /**
- * Constructs a new instance of the HttpUrlConnectionTransportOutputStream based on the given
- * HttpURLConnection.
- */
- public HttpUrlConnectionTransportOutputStream(HttpURLConnection connection) throws IOException {
- Assert.notNull(connection, "connection must not be null");
- this.connection = connection;
- }
-
- public void addHeader(String name, String value) throws IOException {
- connection.setRequestProperty(name, value);
- }
-
- protected OutputStream createOutputStream() throws IOException {
- return connection.getOutputStream();
- }
-}
diff --git a/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionWebServiceConnection.java b/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionWebServiceConnection.java
deleted file mode 100644
index 120186f3..00000000
--- a/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionWebServiceConnection.java
+++ /dev/null
@@ -1,88 +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.transport.http;
-
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.ProtocolException;
-
-import org.springframework.util.Assert;
-import org.springframework.ws.WebServiceMessage;
-import org.springframework.ws.context.MessageContext;
-import org.springframework.ws.transport.TransportOutputStream;
-import org.springframework.ws.transport.WebServiceConnection;
-
-/**
- * Implementation of the {@link WebServiceConnection} interface that uses a {@link HttpURLConnection}.
- *
- * @author Arjen Poutsma
- */
-public class HttpUrlConnectionWebServiceConnection implements WebServiceConnection {
-
- private static final String HTTP_METHOD_POST = "POST";
-
- private final HttpURLConnection connection;
-
- /**
- * Creates a new instance of the HttpUrlConnectionWebServiceConnection with the given
- * HttpURLConnection.
- */
- public HttpUrlConnectionWebServiceConnection(HttpURLConnection connection) {
- Assert.notNull(connection, "connection must not be null");
- this.connection = connection;
- }
-
- public void close() {
- connection.disconnect();
- }
-
- public void sendAndReceive(MessageContext messageContext) throws IOException {
- prepareConnection();
- writeRequestMessage(messageContext.getRequest());
- validateResponse();
- readResponse(messageContext);
- }
-
- private void prepareConnection() throws ProtocolException {
- connection.setRequestMethod(HTTP_METHOD_POST);
- connection.setUseCaches(false);
- connection.setDoInput(true);
- connection.setDoOutput(true);
- }
-
- private void writeRequestMessage(WebServiceMessage message) throws IOException {
- TransportOutputStream tos = new HttpUrlConnectionTransportOutputStream(connection);
- message.writeTo(tos);
- tos.flush();
- }
-
- private void validateResponse() throws IOException {
- int responseCode = connection.getResponseCode();
- if (responseCode != HttpURLConnection.HTTP_INTERNAL_ERROR && responseCode / 100 != 2) {
- throw new HttpTransportException("Did not receive successful HTTP response: status code = " + responseCode +
- ", status message = [" + connection.getResponseMessage() + "]");
- }
- }
-
- private void readResponse(MessageContext messageContext) throws IOException {
- if (connection.getResponseCode() == HttpURLConnection.HTTP_NO_CONTENT || connection.getContentLength() == 0) {
- return;
- }
- messageContext.readResponse(new HttpUrlConnectionTransportInputStream(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 3e975326..e0ae2366 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
@@ -16,15 +16,13 @@
package org.springframework.ws.transport.http;
-import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
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.TransportInputStream;
-import org.springframework.ws.transport.TransportOutputStream;
+import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.WebServiceMessageReceiver;
import org.springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport;
@@ -55,13 +53,13 @@ public class WebServiceMessageReceiverHandlerAdapter extends WebServiceMessageRe
HttpServletResponse httpServletResponse,
Object handler) throws Exception {
if ("POST".equals(httpServletRequest.getMethod())) {
- TransportInputStream tis = new HttpServletTransportInputStream(httpServletRequest);
- TransportOutputStream tos = new HttpServletTransportOutputStream(httpServletResponse);
- handle(tis, tos, (WebServiceMessageReceiver) handler);
+ WebServiceConnection connection = new HttpServletConnection(httpServletRequest, httpServletResponse);
+ handleConnection(connection, (WebServiceMessageReceiver) handler);
return null;
}
else {
- throw new ServletException("Request method '" + httpServletRequest.getMethod() + "' not supported");
+ httpServletResponse.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+ return null;
}
}
@@ -69,35 +67,30 @@ public class WebServiceMessageReceiverHandlerAdapter extends WebServiceMessageRe
return handler instanceof WebServiceMessageReceiver;
}
- /**
- * Sets the response code to 204, No Content.
- */
- protected void handleNoResponse(TransportInputStream tis, TransportOutputStream tos) {
- HttpServletResponse httpServletResponse = ((HttpServletTransportOutputStream) tos).getHttpServletResponse();
- httpServletResponse.setStatus(HttpServletResponse.SC_NO_CONTENT);
+ /** 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(TransportInputStream tis, TransportOutputStream tos, WebServiceMessage response)
- throws Exception {
- HttpServletResponse httpServletResponse = ((HttpServletTransportOutputStream) tos).getHttpServletResponse();
+ 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);
}
- response.writeTo(tos);
+ super.handleResponse(connection, response);
}
- /**
- * Sets the response code to 404, Not Found.
- */
- protected void handleNoEndpointFound(TransportInputStream tis, TransportOutputStream tos) {
- HttpServletResponse httpServletResponse = ((HttpServletTransportOutputStream) tos).getHttpServletResponse();
+ /** 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 88b77573..f2c4cb7e 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
@@ -16,6 +16,8 @@
package org.springframework.ws.transport.support;
+import java.io.IOException;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
@@ -27,6 +29,7 @@ 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.WebServiceConnection;
import org.springframework.ws.transport.WebServiceMessageReceiver;
import org.springframework.ws.transport.context.DefaultTransportContext;
import org.springframework.ws.transport.context.TransportContext;
@@ -34,30 +37,24 @@ import org.springframework.ws.transport.context.TransportContextHolder;
/**
* Convenience base class for server-side transport objects. Contains a {@link WebServiceMessageFactory}, and has
- * methods for handling incoming WebServiceMessage requests.
+ * methods for handling incoming {@link WebServiceConnection}s.
*
* @author Arjen Poutsma
- * @see #handle(org.springframework.ws.transport.TransportInputStream,org.springframework.ws.transport.TransportOutputStream,org.springframework.ws.transport.WebServiceMessageReceiver)
+ * @see #handleConnection
*/
public abstract class WebServiceMessageReceiverObjectSupport implements InitializingBean {
- /**
- * Logger available to subclasses.
- */
+ /** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
private WebServiceMessageFactory messageFactory;
- /**
- * Returns the WebServiceMessageFactory.
- */
+ /** Returns the WebServiceMessageFactory. */
public WebServiceMessageFactory getMessageFactory() {
return messageFactory;
}
- /**
- * Sets the WebServiceMessageFactory.
- */
+ /** Sets the WebServiceMessageFactory. */
public void setMessageFactory(WebServiceMessageFactory messageFactory) {
this.messageFactory = messageFactory;
}
@@ -67,66 +64,92 @@ public abstract class WebServiceMessageReceiverObjectSupport implements Initiali
logger.info("Using message factory [" + messageFactory + "]");
}
- protected final void handle(TransportInputStream tis, TransportOutputStream tos, WebServiceMessageReceiver receiver)
+ /**
+ * Handles an incoming connection by reading a message from the connection input stream, passing it to the receiver,
+ * and writing the response (if any) to the output stream.
+ *
+ * Stores the given connection in the transport context.
+ *
+ * @param connection the incoming connection
+ * @param receiver the handler of the message, typically a {@link org.springframework.ws.server.MessageDispatcher}
+ * @see org.springframework.ws.transport.context.TransportContext
+ */
+ protected final void handleConnection(WebServiceConnection connection, WebServiceMessageReceiver receiver)
throws Exception {
TransportContext previousTransportContext = TransportContextHolder.getTransportContext();
- TransportContextHolder.setTransportContext(new DefaultTransportContext(tis, tos));
+ TransportContextHolder.setTransportContext(new DefaultTransportContext(connection));
try {
- WebServiceMessage messageRequest = getMessageFactory().createWebServiceMessage(tis);
- MessageContext messageContext = new DefaultMessageContext(messageRequest, getMessageFactory());
+ MessageContext messageContext = handleRequest(connection);
receiver.receive(messageContext);
if (!messageContext.hasResponse()) {
- handleNoResponse(tis, tos);
+ handleNoResponse(connection);
}
else {
- handleResponse(tis, tos, messageContext.getResponse());
+ handleResponse(connection, messageContext.getResponse());
}
}
catch (NoEndpointFoundException ex) {
- handleNoEndpointFound(tis, tos);
+ handleNoEndpointFound(connection);
}
finally {
+ try {
+ connection.close();
+ }
+ catch (IOException ex) {
+ logger.debug("Could not close connection", ex);
+ }
TransportContextHolder.setTransportContext(previousTransportContext);
}
}
- /**
- * Invoked from {@link #handle(org.springframework.ws.transport.TransportInputStream,org.springframework.ws.transport.TransportOutputStream,org.springframework.ws.transport.WebServiceMessageReceiver)}
- * when no response is given. Default implementation does nothing. Can be overriden to set certain
- * transport-specific response headers.
- *
- * @param tis the transport input stream
- * @param tos the transport output stream
- */
- protected void handleNoResponse(TransportInputStream tis, TransportOutputStream tos) {
+ 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();
+ }
}
/**
- * Handles the sending of the response. Invoked from {@link #handle(org.springframework.ws.transport.TransportInputStream,org.springframework.ws.transport.TransportOutputStream,org.springframework.ws.transport.WebServiceMessageReceiver)}.
- * Default implementation writes the given response to the given TransportOutputStream. Can be
- * overriden to set certain transport-specific headers.
+ * Invoked from {@link #handleConnection} when no response is given. Default implementation does nothing. Can be
+ * overriden to set certain transport-specific response headers.
*
- * @param tis the transport input stream
- * @param tos the transport output stream
- * @param response the response message
+ * @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(TransportInputStream tis, TransportOutputStream tos, WebServiceMessage response)
- throws Exception {
- response.writeTo(tos);
- tos.flush();
+ 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 #handle(org.springframework.ws.transport.TransportInputStream,org.springframework.ws.transport.TransportOutputStream,org.springframework.ws.transport.WebServiceMessageReceiver)}
- * when no suitable endpoint is found. Default implementation does nothing. Can be overriden to set certain
- * transport-specific response headers.
+ * 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 tis the transport input stream
- * @param tos the transport output stream
+ * @param connection the incoming connection
*/
- protected void handleNoEndpointFound(TransportInputStream tis, TransportOutputStream tos) {
+ protected void handleNoEndpointFound(WebServiceConnection connection) {
}
}
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
new file mode 100644
index 00000000..c4057aa1
--- /dev/null
+++ b/core/src/test/java/org/springframework/ws/client/core/SimpleSaajServlet.java
@@ -0,0 +1,122 @@
+/*
+ * 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.core;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.soap.MessageFactory;
+import javax.xml.soap.MimeHeader;
+import javax.xml.soap.MimeHeaders;
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPMessage;
+
+/**
+ * A simple Servlet that uses SAAJ to echo request.
+ *
+ * @author Arjen Poutsma
+ */
+public class SimpleSaajServlet extends HttpServlet {
+
+ private MessageFactory msgFactory = null;
+
+ public void init(ServletConfig servletConfig) throws ServletException {
+ super.init(servletConfig);
+ try {
+ msgFactory = MessageFactory.newInstance();
+ }
+ catch (SOAPException ex) {
+ throw new ServletException("Unable to create message factory" + ex.getMessage());
+ }
+ }
+
+ private MimeHeaders getHeaders(HttpServletRequest httpServletRequest) {
+ Enumeration enumeration = httpServletRequest.getHeaderNames();
+ MimeHeaders headers = new MimeHeaders();
+
+ while (enumeration.hasMoreElements()) {
+ String headerName = (String) enumeration.nextElement();
+ String headerValue = httpServletRequest.getHeader(headerName);
+
+ StringTokenizer values = new StringTokenizer(headerValue, ",");
+
+ while (values.hasMoreTokens()) {
+ headers.addHeader(headerName, values.nextToken().trim());
+ }
+ }
+
+ return headers;
+ }
+
+ private void putHeaders(MimeHeaders headers, HttpServletResponse res) {
+ Iterator it = headers.getAllHeaders();
+
+ while (it.hasNext()) {
+ MimeHeader header = (MimeHeader) it.next();
+
+ String[] values = headers.getHeader(header.getName());
+
+ if (values.length == 1) {
+ res.setHeader(header.getName(), header.getValue());
+ }
+ else {
+ StringBuffer concat = new StringBuffer();
+ int i = 0;
+
+ while (i < values.length) {
+ if (i != 0) {
+ concat.append(',');
+ }
+ concat.append(values[i++]);
+ }
+ res.setHeader(header.getName(), concat.toString());
+ }
+ }
+ }
+
+ public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ try {
+ MimeHeaders headers = getHeaders(req);
+ SOAPMessage msg = msgFactory.createMessage(headers, req.getInputStream());
+ SOAPMessage reply = onMessage(msg);
+ resp.setStatus(HttpServletResponse.SC_OK);
+ if (reply != null) {
+ if (reply.saveRequired()) {
+ reply.saveChanges();
+ }
+ resp.setStatus(HttpServletResponse.SC_OK);
+ putHeaders(reply.getMimeHeaders(), resp);
+ reply.writeTo(resp.getOutputStream());
+ }
+ }
+ catch (Exception ex) {
+ throw new ServletException("SAAJ POST failed " + ex.getMessage());
+ }
+ }
+
+ public SOAPMessage onMessage(SOAPMessage message) {
+ return message;
+ }
+
+
+}
diff --git a/core/src/test/java/org/springframework/ws/client/core/WebServiceTemplateIntegrationTest.java b/core/src/test/java/org/springframework/ws/client/core/WebServiceTemplateIntegrationTest.java
new file mode 100644
index 00000000..0adc740d
--- /dev/null
+++ b/core/src/test/java/org/springframework/ws/client/core/WebServiceTemplateIntegrationTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.core;
+
+import java.net.URL;
+import javax.xml.soap.MessageFactory;
+
+import org.custommonkey.xmlunit.XMLTestCase;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.servlet.Context;
+import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
+import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
+import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender;
+import org.springframework.xml.transform.StringResult;
+import org.springframework.xml.transform.StringSource;
+
+public class WebServiceTemplateIntegrationTest extends XMLTestCase {
+
+ private WebServiceTemplate template;
+
+ private Server jettyServer;
+
+ protected void setUp() throws Exception {
+ jettyServer = new Server(8085);
+ Context jettyContext = new Context(jettyServer, "/");
+ jettyContext.addServlet(SimpleSaajServlet.class, "/");
+ jettyServer.start();
+ template = new WebServiceTemplate();
+ HttpUrlConnectionMessageSender messageSender = new HttpUrlConnectionMessageSender();
+ messageSender.setUrl(new URL("http://localhost:8085/"));
+ template.setMessageSender(messageSender);
+ }
+
+ protected void tearDown() throws Exception {
+ jettyServer.stop();
+ }
+
+ public void testSendAndReceiveSaaj() throws Exception {
+ template.setMessageFactory(new SaajSoapMessageFactory(MessageFactory.newInstance()));
+ String content = "