Updated Transport API.

This commit is contained in:
Arjen Poutsma
2007-04-10 21:27:47 +00:00
parent 7437ee78f5
commit 7d9405e8a2
10 changed files with 364 additions and 258 deletions

View File

@@ -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.transport;
import java.io.IOException;
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.
*
* @author Arjen Poutsma
*/
public abstract class AbstractReceivingWebServiceConnection implements WebServiceConnection {
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
private TransportInputStream requestInputStream;
private TransportOutputStream responseOutputStream;
public final TransportInputStream getTransportInputStream() throws IOException {
if (requestInputStream == null) {
requestInputStream = new RequestTransportInputStream();
}
return requestInputStream;
}
public final TransportOutputStream getTransportOutputStream() throws IOException {
if (responseOutputStream == null) {
responseOutputStream = new ResponseTransportOutputStream();
}
return responseOutputStream;
}
/**
* Returns an iteration over all the header names this request contains. Returns an empty <code>Iterator</code> if
* there areno headers.
*/
protected abstract Iterator getRequestHeaderNames() throws IOException;
/**
* Returns an iteration over all the string values of the specified header. Returns an empty <code>Iterator</code>
* if there are no headers of the specified name.
*/
protected abstract Iterator getRequestHeaders(String name) throws IOException;
/** Returns the input stream to read the response from. */
protected abstract InputStream getRequestInputStream() throws IOException;
/**
* Adds a response header with the given name and value. This method can be called multiple times, to allow for
* headers with multiple values.
*
* @param name the name of the header
* @param value the value of the header
*/
protected abstract void addResponseHeader(String name, String value) throws IOException;
/** 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 <code>TransportInputStream</code> for receiving-side connections. */
private class RequestTransportInputStream extends TransportInputStream {
protected InputStream createInputStream() throws IOException {
return getRequestInputStream();
}
public Iterator getHeaderNames() throws IOException {
return getRequestHeaderNames();
}
public Iterator getHeaders(String name) throws IOException {
return getRequestHeaders(name);
}
}
/** Implementation of <code>TransportOutputStream</code> for sending-side connections. */
private class ResponseTransportOutputStream extends TransportOutputStream {
public void addHeader(String name, String value) throws IOException {
addResponseHeader(name, value);
}
protected OutputStream createOutputStream() throws IOException {
return getResponseOutputStream();
}
public void close() throws IOException {
super.close();
sendResponse();
}
}
}

View File

@@ -0,0 +1,127 @@
/*
* 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 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());
private TransportOutputStream requestOutputStream;
private TransportInputStream responseInputStream;
public final TransportOutputStream getTransportOutputStream() throws IOException {
if (requestOutputStream == null) {
requestOutputStream = new RequestTransportOutputStream();
}
return requestOutputStream;
}
public final TransportInputStream getTransportInputStream() throws IOException {
if (hasResponse()) {
if (responseInputStream == null) {
responseInputStream = new ResponseTransportInputStream();
}
return responseInputStream;
}
else {
return null;
}
}
/** Indicates whether this connection has a response. */
protected abstract boolean hasResponse() throws IOException;
/**
* Adds a request header with the given name and value. This method can be called multiple times, to allow for
* headers with multiple values.
*
* @param name the name of the header
* @param value the value of the header
*/
protected abstract void addRequestHeader(String name, String value) throws IOException;
/** 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 <code>Iterator</code> if
* there areno headers.
*/
protected abstract Iterator getResponseHeaderNames() throws IOException;
/**
* Returns an iteration over all the string values of the specified header. Returns an empty <code>Iterator</code>
* if there are no headers of the specified name.
*/
protected abstract Iterator getResponseHeaders(String name) throws IOException;
/** Returns the input stream to read the response from. */
protected abstract InputStream getResponseInputStream() throws IOException;
/** Implementation of <code>TransportInputStream</code> for receiving-side connections. */
class RequestTransportOutputStream extends TransportOutputStream {
public void addHeader(String name, String value) throws IOException {
addRequestHeader(name, value);
}
protected OutputStream createOutputStream() throws IOException {
return getRequestOutputStream();
}
public void close() throws IOException {
super.close();
sendRequest();
}
}
/** Implementation of {@link TransportInputStream} for client-side HTTP. */
class ResponseTransportInputStream extends TransportInputStream {
protected InputStream createInputStream() throws IOException {
return getResponseInputStream();
}
public Iterator getHeaderNames() throws IOException {
return getResponseHeaderNames();
}
public Iterator getHeaders(String name) throws IOException {
return getResponseHeaders(name);
}
}
}

View File

@@ -1,60 +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;
import java.io.IOException;
/**
* Abstract base class for {@link WebServiceConnection} implementations.
*
* @author Arjen Poutsma
*/
public abstract class AbstractWebServiceConnection implements WebServiceConnection {
private TransportOutputStream tos;
private TransportInputStream tis;
public final TransportOutputStream getTransportOutputStream() throws IOException {
if (tos == null) {
tos = createTransportOutputStream();
}
return tos;
}
public final TransportInputStream getTransportInputStream() throws IOException {
if (hasResponse()) {
if (tis == null) {
tis = createTransportInputStream();
}
return tis;
}
else {
return null;
}
}
/** Creates a new <code>TransportOutputStream</code>. The result is cached in a local variable. */
protected abstract TransportOutputStream createTransportOutputStream() throws IOException;
/** Creates a new <code>TransportInputStream</code>. The result is cached in a local variable. */
protected abstract TransportInputStream createTransportInputStream() throws IOException;
/** Indicates whether this connection has a response. */
protected abstract boolean hasResponse() throws IOException;
}

View File

@@ -91,20 +91,18 @@ public abstract class TransportInputStream extends InputStream {
return getInputStream().read();
}
/**
* Returns the input stream to read from.
*/
/** Returns the input stream to read from. */
protected abstract InputStream createInputStream() throws IOException;
/**
* Returns an iteration over all the header names this request contains. Returns an empty <code>Iterator</code> if
* the request has no headers.
* Returns an iteration over all the header names this stream contains. Returns an empty <code>Iterator</code> if
* there are no headers.
*/
public abstract Iterator getHeaderNames() throws IOException;
/**
* Returns an iteration over all the string values of the specified request header. Returns an empty
* <code>Iterator</code> if the request did not include any headers of the specified name.
* Returns an iteration over all the string values of the specified header. Returns an empty <code>Iterator</code>
* if there are no headers of the specified name.
*/
public abstract Iterator getHeaders(String name) throws IOException;
}

View File

@@ -64,16 +64,14 @@ public abstract class TransportOutputStream extends OutputStream {
}
/**
* Adds a response header with the given name and value. This method can be called multiple times, to allow for
* headers with multiple values.
* Adds a header with the given name and value. This method can be called multiple times, to allow for headers with
* multiple values.
*
* @param name the name of the header
* @param value the value of the header
*/
public abstract void addHeader(String name, String value) throws IOException;
/**
* Returns the output stream to write to.
*/
/** Returns the output stream to write to. */
protected abstract OutputStream createOutputStream() throws IOException;
}

View File

@@ -0,0 +1,72 @@
/*
* 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.util.Iterator;
import java.util.zip.GZIPInputStream;
import org.springframework.ws.transport.AbstractSendingWebServiceConnection;
import org.springframework.ws.transport.FaultAwareWebServiceConnection;
import org.springframework.ws.transport.WebServiceConnection;
/**
* Abstract base class for {@link WebServiceConnection} implementations that send request over HTTP.
*
* @author Arjen Poutsma
*/
public abstract class AbstractHttpSendingWebServiceConnection extends AbstractSendingWebServiceConnection
implements FaultAwareWebServiceConnection {
protected static final String HTTP_HEADER_CONTENT_ENCODING = "Content-Encoding";
protected static final String ENCODING_GZIP = "gzip";
protected static final int HTTP_STATUS_INTERNAL_ERROR = 500;
protected final boolean hasResponse() throws IOException {
return getResponseContentLength() > 0;
}
public final boolean hasFault() throws IOException {
return getResponseCode() == HTTP_STATUS_INTERNAL_ERROR;
}
protected final InputStream getResponseInputStream() throws IOException {
return isGzipResponse() ? new GZIPInputStream(getRawResponseInputStream()) : getRawResponseInputStream();
}
/** Determine whether the given response is a GZIP response. */
private boolean isGzipResponse() throws IOException {
for (Iterator iterator = getResponseHeaders(HTTP_HEADER_CONTENT_ENCODING); iterator.hasNext();) {
String encodingHeader = (String) iterator.next();
return encodingHeader.toLowerCase().indexOf(ENCODING_GZIP) != -1;
}
return false;
}
/** Returns the HTTP status code of the response. */
protected abstract int getResponseCode() throws IOException;
/** Returns the length of the response. */
protected abstract long getResponseContentLength() throws IOException;
protected abstract InputStream getRawResponseInputStream() throws IOException;
}

View File

@@ -1,125 +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.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.zip.GZIPInputStream;
import org.springframework.ws.transport.AbstractWebServiceConnection;
import org.springframework.ws.transport.FaultAwareWebServiceConnection;
import org.springframework.ws.transport.TransportInputStream;
import org.springframework.ws.transport.TransportOutputStream;
import org.springframework.ws.transport.WebServiceConnection;
/**
* Abstract base class for {@link WebServiceConnection} implementations that use HTTP.
*
* @author Arjen Poutsma
*/
public abstract class AbstractHttpWebServiceConnection extends AbstractWebServiceConnection
implements FaultAwareWebServiceConnection {
protected static final String HTTP_HEADER_CONTENT_ENCODING = "Content-Encoding";
protected static final String ENCODING_GZIP = "gzip";
protected static final int HTTP_STATUS_INTERNAL_ERROR = 500;
protected final TransportOutputStream createTransportOutputStream() throws IOException {
return new HttpClientTransportOutputStream();
}
protected final boolean hasResponse() throws IOException {
return getResponseContentLength() > 0;
}
protected final TransportInputStream createTransportInputStream() throws IOException {
return new HttpClientTransportInputStream();
}
public final boolean hasFault() throws IOException {
return getResponseCode() == HTTP_STATUS_INTERNAL_ERROR;
}
private InputStream getUncompressedResponseInputStream() throws IOException {
return isGzipResponse() ? new GZIPInputStream(getResponseInputStream()) : getResponseInputStream();
}
/** Determine whether the given response is a GZIP response. */
private boolean isGzipResponse() throws IOException {
for (Iterator iterator = getResponseHeaders(HTTP_HEADER_CONTENT_ENCODING); iterator.hasNext();) {
String encodingHeader = (String) iterator.next();
return encodingHeader.toLowerCase().indexOf(ENCODING_GZIP) != -1;
}
return false;
}
protected abstract void addRequestHeader(String name, String value) throws IOException;
protected abstract OutputStream getRequestOutputStream() throws IOException;
protected abstract void open() throws IOException;
protected abstract int getResponseCode() throws IOException;
protected abstract long getResponseContentLength() throws IOException;
protected abstract Iterator getResponseHeaderNames() throws IOException;
protected abstract Iterator getResponseHeaders(String name) throws IOException;
protected abstract InputStream getResponseInputStream() throws IOException;
/** Implementation of {@link TransportOutputStream} for client-side HTTP. */
class HttpClientTransportOutputStream extends TransportOutputStream {
public void addHeader(String name, String value) throws IOException {
addRequestHeader(name, value);
}
protected OutputStream createOutputStream() throws IOException {
return getRequestOutputStream();
}
public void close() throws IOException {
super.close();
open();
}
}
/** Implementation of {@link TransportInputStream} for client-side HTTP. */
class HttpClientTransportInputStream extends TransportInputStream {
protected InputStream createInputStream() throws IOException {
return getUncompressedResponseInputStream();
}
public Iterator getHeaderNames() throws IOException {
return getResponseHeaderNames();
}
public Iterator getHeaders(String name) throws IOException {
return getResponseHeaders(name);
}
}
}

View File

@@ -37,7 +37,7 @@ import org.springframework.ws.transport.WebServiceConnection;
*
* @author Arjen Poutsma
*/
public class CommonsHttpConnection extends AbstractHttpWebServiceConnection {
public class CommonsHttpConnection extends AbstractHttpSendingWebServiceConnection {
private final HttpClient httpClient;
@@ -64,7 +64,7 @@ public class CommonsHttpConnection extends AbstractHttpWebServiceConnection {
return bufferedOutput;
}
protected void open() throws IOException {
protected void sendRequest() throws IOException {
postMethod.setRequestEntity(new ByteArrayRequestEntity(bufferedOutput.toByteArray()));
bufferedOutput = null;
httpClient.executeMethod(postMethod);
@@ -78,7 +78,7 @@ public class CommonsHttpConnection extends AbstractHttpWebServiceConnection {
return postMethod.getResponseContentLength();
}
protected InputStream getResponseInputStream() throws IOException {
protected InputStream getRawResponseInputStream() throws IOException {
if (postMethod.getStatusCode() != HttpStatus.SC_INTERNAL_SERVER_ERROR &&
postMethod.getStatusCode() / 100 != 2) {
throw new HttpTransportException("Did not receive successful HTTP response: status code = " +

View File

@@ -23,92 +23,66 @@ 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.AbstractReceivingWebServiceConnection;
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}.
* Implementation of {@link WebServiceConnection} that is based on the Servlet API.
*
* @author Arjen Poutsma
* @author Arjen Poutsma
* @see #getHttpServletRequest()
* @see #getHttpServletResponse()
*/
public class HttpServletConnection implements WebServiceConnection {
public class HttpServletConnection extends AbstractReceivingWebServiceConnection {
private final HttpServletRequest httpServletRequest;
private final HttpServletRequest request;
private final HttpServletResponse httpServletResponse;
private final HttpServletResponse response;
/**
* Constructs a new servlet connection with the given <code>HttpServletRequest</code> and
* <code>HttpServletResponse</code>.
*/
public HttpServletConnection(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
this.httpServletRequest = httpServletRequest;
this.httpServletResponse = httpServletResponse;
request = httpServletRequest;
response = httpServletResponse;
}
/** Returns the <code>HttpServletRequest</code> for this connection. */
public HttpServletRequest getHttpServletRequest() {
return httpServletRequest;
return request;
}
/** Returns the <code>HttpServletResponse</code> for this connection. */
public HttpServletResponse getHttpServletResponse() {
return httpServletResponse;
return response;
}
public TransportInputStream getTransportInputStream() {
return new HttpServletTransportInputStream();
protected Iterator getRequestHeaderNames() throws IOException {
return new EnumerationIterator(request.getHeaderNames());
}
public TransportOutputStream getTransportOutputStream() {
return new HttpServletTransportOutputStream();
protected Iterator getRequestHeaders(String name) throws IOException {
return new EnumerationIterator(request.getHeaders(name));
}
protected InputStream getRequestInputStream() throws IOException {
return request.getInputStream();
}
protected void addResponseHeader(String name, String value) throws IOException {
response.addHeader(name, value);
}
protected OutputStream getResponseOutputStream() throws IOException {
return response.getOutputStream();
}
protected void sendResponse() throws IOException {
// no op
}
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);
}
}
}

View File

@@ -35,7 +35,7 @@ import org.springframework.ws.transport.WebServiceConnection;
*
* @author Arjen Poutsma
*/
public class HttpUrlConnection extends AbstractHttpWebServiceConnection {
public class HttpUrlConnection extends AbstractHttpSendingWebServiceConnection {
private final HttpURLConnection connection;
@@ -61,7 +61,7 @@ public class HttpUrlConnection extends AbstractHttpWebServiceConnection {
return connection.getOutputStream();
}
protected void open() throws IOException {
protected void sendRequest() throws IOException {
connection.connect();
}
@@ -99,7 +99,7 @@ public class HttpUrlConnection extends AbstractHttpWebServiceConnection {
return connection.getResponseCode();
}
protected InputStream getResponseInputStream() throws IOException {
protected InputStream getRawResponseInputStream() throws IOException {
if (connection.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR) {
return connection.getErrorStream();
}