KickJava   Java API By Example, From Geeks To Geeks.

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


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.net.HttpURLConnection JavaDoc;
23 import java.net.URL JavaDoc;
24 import java.net.URLConnection JavaDoc;
25 import java.util.zip.GZIPInputStream JavaDoc;
26
27 import org.springframework.remoting.support.RemoteInvocationResult;
28
29 /**
30  * HttpInvokerRequestExecutor implementation that uses standard J2SE facilities
31  * to execute POST requests, without support for HTTP authentication or
32  * advanced configuration options.
33  *
34  * <p>Designed for easy subclassing, customizing specific template methods.
35  * However, consider CommonsHttpInvokerRequestExecutor for more sophisticated
36  * needs: The J2SE HttpURLConnection is rather limited in its capabilities.
37  *
38  * @author Juergen Hoeller
39  * @since 1.1
40  * @see CommonsHttpInvokerRequestExecutor
41  * @see java.net.HttpURLConnection
42  */

43 public class SimpleHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {
44
45     /**
46      * Execute the given request through a standard J2SE HttpURLConnection.
47      * <p>This method implements the basic processing workflow:
48      * The actual work happens in this class's template methods.
49      * @see #openConnection
50      * @see #prepareConnection
51      * @see #writeRequestBody
52      * @see #validateResponse
53      * @see #readResponseBody
54      */

55     protected RemoteInvocationResult doExecuteRequest(
56             HttpInvokerClientConfiguration config, ByteArrayOutputStream JavaDoc baos)
57             throws IOException JavaDoc, ClassNotFoundException JavaDoc {
58
59         HttpURLConnection JavaDoc con = openConnection(config);
60         prepareConnection(con, baos.size());
61         writeRequestBody(config, con, baos);
62         validateResponse(config, con);
63         InputStream JavaDoc responseBody = readResponseBody(config, con);
64
65         return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());
66     }
67
68     /**
69      * Open an HttpURLConnection for the given remote invocation request.
70      * @param config the HTTP invoker configuration that specifies the
71      * target service
72      * @return the HttpURLConnection for the given request
73      * @throws IOException if thrown by I/O methods
74      * @see java.net.URL#openConnection()
75      */

76     protected HttpURLConnection JavaDoc openConnection(HttpInvokerClientConfiguration config) throws IOException JavaDoc {
77         URLConnection JavaDoc con = new URL JavaDoc(config.getServiceUrl()).openConnection();
78         if (!(con instanceof HttpURLConnection JavaDoc)) {
79             throw new IOException JavaDoc("Service URL [" + config.getServiceUrl() + "] is not an HTTP URL");
80         }
81         return (HttpURLConnection JavaDoc) con;
82     }
83
84     /**
85      * Prepare the given HTTP connection.
86      * <p>The default implementation specifies POST as method,
87      * "application/x-java-serialized-object" as "Content-Type" header,
88      * and the given content length as "Content-Length" header.
89      * @param con the HTTP connection to prepare
90      * @param contentLength the length of the content to send
91      * @throws IOException if thrown by HttpURLConnection methods
92      * @see java.net.HttpURLConnection#setRequestMethod
93      * @see java.net.HttpURLConnection#setRequestProperty
94      */

95     protected void prepareConnection(HttpURLConnection JavaDoc con, int contentLength) throws IOException JavaDoc {
96         con.setDoOutput(true);
97         con.setRequestMethod(HTTP_METHOD_POST);
98         con.setRequestProperty(HTTP_HEADER_CONTENT_TYPE, getContentType());
99         con.setRequestProperty(HTTP_HEADER_CONTENT_LENGTH, Integer.toString(contentLength));
100         if (isAcceptGzipEncoding()) {
101             con.setRequestProperty(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
102         }
103     }
104
105     /**
106      * Set the given serialized remote invocation as request body.
107      * <p>The default implementation simply write the serialized invocation to the
108      * HttpURLConnection's OutputStream. This can be overridden, for example, to write
109      * a specific encoding and potentially set appropriate HTTP request headers.
110      * @param config the HTTP invoker configuration that specifies the target service
111      * @param con the HttpURLConnection to write the request body to
112      * @param baos the ByteArrayOutputStream that contains the serialized
113      * RemoteInvocation object
114      * @throws IOException if thrown by I/O methods
115      * @see java.net.HttpURLConnection#getOutputStream()
116      * @see java.net.HttpURLConnection#setRequestProperty
117      */

118     protected void writeRequestBody(
119             HttpInvokerClientConfiguration config, HttpURLConnection JavaDoc con, ByteArrayOutputStream JavaDoc baos)
120             throws IOException JavaDoc {
121
122         baos.writeTo(con.getOutputStream());
123     }
124
125     /**
126      * Validate the given response as contained in the HttpURLConnection object,
127      * throwing an exception if it does not correspond to a successful HTTP response.
128      * <p>Default implementation rejects any HTTP status code beyond 2xx, to avoid
129      * parsing the response body and trying to deserialize from a corrupted stream.
130      * @param config the HTTP invoker configuration that specifies the target service
131      * @param con the HttpURLConnection to validate
132      * @throws IOException if validation failed
133      * @see java.net.HttpURLConnection#getResponseCode()
134      */

135     protected void validateResponse(HttpInvokerClientConfiguration config, HttpURLConnection JavaDoc con)
136             throws IOException JavaDoc {
137
138         if (con.getResponseCode() >= 300) {
139             throw new IOException JavaDoc(
140                     "Did not receive successful HTTP response: status code = " + con.getResponseCode() +
141                     ", status message = [" + con.getResponseMessage() + "]");
142         }
143     }
144
145     /**
146      * Extract the response body from the given executed remote invocation
147      * request.
148      * <p>The default implementation simply reads the serialized invocation
149      * from the HttpURLConnection's InputStream. If the response is recognized
150      * as GZIP response, the InputStream will get wrapped in a GZIPInputStream.
151      * @param config the HTTP invoker configuration that specifies the target service
152      * @param con the HttpURLConnection to read the response body from
153      * @return an InputStream for the response body
154      * @throws IOException if thrown by I/O methods
155      * @see #isGzipResponse
156      * @see java.util.zip.GZIPInputStream
157      * @see java.net.HttpURLConnection#getInputStream()
158      * @see java.net.HttpURLConnection#getHeaderField(int)
159      * @see java.net.HttpURLConnection#getHeaderFieldKey(int)
160      */

161     protected InputStream JavaDoc readResponseBody(HttpInvokerClientConfiguration config, HttpURLConnection JavaDoc con)
162             throws IOException JavaDoc {
163
164         if (isGzipResponse(con)) {
165             // GZIP response found - need to unzip.
166
return new GZIPInputStream JavaDoc(con.getInputStream());
167         }
168         else {
169             // Plain response found.
170
return con.getInputStream();
171         }
172     }
173
174     /**
175      * Determine whether the given response is a GZIP response.
176      * <p>Default implementation checks whether the HTTP "Content-Encoding"
177      * header contains "gzip" (in any casing).
178      * @param con the HttpURLConnection to check
179      */

180     protected boolean isGzipResponse(HttpURLConnection JavaDoc con) {
181         String JavaDoc encodingHeader = con.getHeaderField(HTTP_HEADER_CONTENT_ENCODING);
182         return (encodingHeader != null && encodingHeader.toLowerCase().indexOf(ENCODING_GZIP) != -1);
183     }
184
185 }
186
Popular Tags