KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > remoting > httpinvoker > CommonsHttpInvokerRequestExecutor


1 /*
2  * Copyright 2002-2006 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.remoting.httpinvoker;
18
19 import java.io.ByteArrayOutputStream JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.io.InputStream JavaDoc;
22 import java.util.zip.GZIPInputStream JavaDoc;
23
24 import org.apache.commons.httpclient.Header;
25 import org.apache.commons.httpclient.HttpClient;
26 import org.apache.commons.httpclient.HttpException;
27 import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
28 import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
29 import org.apache.commons.httpclient.methods.PostMethod;
30
31 import org.springframework.remoting.support.RemoteInvocationResult;
32
33 /**
34  * HttpInvokerRequestExecutor implementation that uses
35  * <a HREF="http://jakarta.apache.org/commons/httpclient">Jakarta Commons HttpClient</a>
36  * to execute POST requests. Compatible with Commons HttpClient 2.0 and 3.0.
37  *
38  * <p>Allows to use a preconfigured HttpClient instance, potentially
39  * with authentication, HTTP connection pooling, etc. Also designed
40  * for easy subclassing, customizing specific template methods.
41  *
42  * @author Juergen Hoeller
43  * @since 1.1
44  * @see SimpleHttpInvokerRequestExecutor
45  */

46 public class CommonsHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {
47
48     private HttpClient httpClient;
49
50
51     /**
52      * Create a new CommonsHttpInvokerRequestExecutor with a default
53      * HttpClient that uses a default MultiThreadedHttpConnectionManager.
54      * @see org.apache.commons.httpclient.HttpClient
55      * @see org.apache.commons.httpclient.MultiThreadedHttpConnectionManager
56      */

57     public CommonsHttpInvokerRequestExecutor() {
58         this.httpClient = new HttpClient(new MultiThreadedHttpConnectionManager());
59     }
60
61     /**
62      * Create a new CommonsHttpInvokerRequestExecutor with the given
63      * HttpClient instance.
64      * @param httpClient the HttpClient instance to use for this request executor
65      */

66     public CommonsHttpInvokerRequestExecutor(HttpClient httpClient) {
67         this.httpClient = httpClient;
68     }
69
70     /**
71      * Set the HttpClient instance to use for this request executor.
72      */

73     public void setHttpClient(HttpClient httpClient) {
74         this.httpClient = httpClient;
75     }
76
77     /**
78      * Return the HttpClient instance that this request executor uses.
79      */

80     public HttpClient getHttpClient() {
81         return httpClient;
82     }
83
84
85     /**
86      * Execute the given request through Commons HttpClient.
87      * <p>This method implements the basic processing workflow:
88      * The actual work happens in this class's template methods.
89      * @see #createPostMethod
90      * @see #setRequestBody
91      * @see #executePostMethod
92      * @see #validateResponse
93      * @see #getResponseBody
94      */

95     protected RemoteInvocationResult doExecuteRequest(
96             HttpInvokerClientConfiguration config, ByteArrayOutputStream JavaDoc baos)
97             throws IOException JavaDoc, ClassNotFoundException JavaDoc {
98
99         PostMethod postMethod = createPostMethod(config);
100         try {
101             setRequestBody(config, postMethod, baos);
102             executePostMethod(config, getHttpClient(), postMethod);
103             validateResponse(config, postMethod);
104             InputStream JavaDoc responseBody = getResponseBody(config, postMethod);
105             return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());
106         }
107         finally {
108             // Need to explicitly release because it might be pooled.
109
postMethod.releaseConnection();
110         }
111     }
112
113     /**
114      * Create a PostMethod for the given configuration.
115      * <p>The default implementation creates a standard PostMethod with
116      * "application/x-java-serialized-object" as "Content-Type" header.
117      * @param config the HTTP invoker configuration that specifies the
118      * target service
119      * @return the PostMethod instance
120      * @throws IOException if thrown by I/O methods
121      */

122     protected PostMethod createPostMethod(HttpInvokerClientConfiguration config) throws IOException JavaDoc {
123         PostMethod postMethod = new PostMethod(config.getServiceUrl());
124         if (isAcceptGzipEncoding()) {
125             postMethod.addRequestHeader(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
126         }
127         return postMethod;
128     }
129
130     /**
131      * Set the given serialized remote invocation as request body.
132      * <p>The default implementation simply sets the serialized invocation
133      * as the PostMethod's request body. This can be overridden, for example,
134      * to write a specific encoding and potentially set appropriate HTTP
135      * request headers.
136      * @param config the HTTP invoker configuration that specifies the target service
137      * @param postMethod the PostMethod to set the request body on
138      * @param baos the ByteArrayOutputStream that contains the serialized
139      * RemoteInvocation object
140      * @throws IOException if thrown by I/O methods
141      * @see org.apache.commons.httpclient.methods.PostMethod#setRequestBody(java.io.InputStream)
142      * @see org.apache.commons.httpclient.methods.PostMethod#setRequestEntity
143      * @see org.apache.commons.httpclient.methods.InputStreamRequestEntity
144      */

145     protected void setRequestBody(
146             HttpInvokerClientConfiguration config, PostMethod postMethod, ByteArrayOutputStream JavaDoc baos)
147             throws IOException JavaDoc {
148
149         postMethod.setRequestEntity(new ByteArrayRequestEntity(baos.toByteArray(), getContentType()));
150     }
151
152     /**
153      * Execute the given PostMethod instance.
154      * @param config the HTTP invoker configuration that specifies the target service
155      * @param httpClient the HttpClient to execute on
156      * @param postMethod the PostMethod to execute
157      * @throws IOException if thrown by I/O methods
158      * @see org.apache.commons.httpclient.HttpClient#executeMethod(org.apache.commons.httpclient.HttpMethod)
159      */

160     protected void executePostMethod(
161             HttpInvokerClientConfiguration config, HttpClient httpClient, PostMethod postMethod)
162             throws IOException JavaDoc {
163
164         httpClient.executeMethod(postMethod);
165     }
166
167     /**
168      * Validate the given response as contained in the PostMethod object,
169      * throwing an exception if it does not correspond to a successful HTTP response.
170      * <p>Default implementation rejects any HTTP status code beyond 2xx, to avoid
171      * parsing the response body and trying to deserialize from a corrupted stream.
172      * @param config the HTTP invoker configuration that specifies the target service
173      * @param postMethod the executed PostMethod to validate
174      * @throws IOException if validation failed
175      * @see org.apache.commons.httpclient.methods.PostMethod#getStatusCode()
176      * @see org.apache.commons.httpclient.HttpException
177      */

178     protected void validateResponse(HttpInvokerClientConfiguration config, PostMethod postMethod)
179             throws IOException JavaDoc {
180
181         if (postMethod.getStatusCode() >= 300) {
182             throw new HttpException(
183                     "Did not receive successful HTTP response: status code = " + postMethod.getStatusCode() +
184                     ", status message = [" + postMethod.getStatusText() + "]");
185         }
186     }
187
188     /**
189      * Extract the response body from the given executed remote invocation
190      * request.
191      * <p>The default implementation simply fetches the PostMethod's response
192      * body stream. If the response is recognized as GZIP response, the
193      * InputStream will get wrapped in a GZIPInputStream.
194      * @param config the HTTP invoker configuration that specifies the target service
195      * @param postMethod the PostMethod to read the response body from
196      * @return an InputStream for the response body
197      * @throws IOException if thrown by I/O methods
198      * @see #isGzipResponse
199      * @see java.util.zip.GZIPInputStream
200      * @see org.apache.commons.httpclient.methods.PostMethod#getResponseBodyAsStream()
201      * @see org.apache.commons.httpclient.methods.PostMethod#getResponseHeader(String)
202      */

203     protected InputStream JavaDoc getResponseBody(HttpInvokerClientConfiguration config, PostMethod postMethod)
204             throws IOException JavaDoc {
205
206         if (isGzipResponse(postMethod)) {
207             return new GZIPInputStream JavaDoc(postMethod.getResponseBodyAsStream());
208         }
209         else {
210             return postMethod.getResponseBodyAsStream();
211         }
212     }
213
214     /**
215      * Determine whether the given response is a GZIP response.
216      * <p>Default implementation checks whether the HTTP "Content-Encoding"
217      * header contains "gzip" (in any casing).
218      * @param postMethod the PostMethod to check
219      */

220     protected boolean isGzipResponse(PostMethod postMethod) {
221         Header encodingHeader = postMethod.getResponseHeader(HTTP_HEADER_CONTENT_ENCODING);
222         if (encodingHeader == null || encodingHeader.getValue() == null) {
223             return false;
224         }
225         return (encodingHeader.getValue().toLowerCase().indexOf(ENCODING_GZIP) != -1);
226     }
227
228 }
229
Popular Tags