KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Copyright 2002-2007 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.io.ObjectInputStream JavaDoc;
23 import java.io.ObjectOutputStream JavaDoc;
24 import java.io.OutputStream JavaDoc;
25 import java.rmi.RemoteException JavaDoc;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29
30 import org.springframework.beans.factory.BeanClassLoaderAware;
31 import org.springframework.remoting.rmi.CodebaseAwareObjectInputStream;
32 import org.springframework.remoting.support.RemoteInvocation;
33 import org.springframework.remoting.support.RemoteInvocationResult;
34 import org.springframework.util.Assert;
35
36 /**
37  * Abstract base implementation of the HttpInvokerRequestExecutor interface.
38  *
39  * <p>Pre-implements serialization of RemoteInvocation objects and
40  * deserialization of RemoteInvocationResults objects.
41  *
42  * @author Juergen Hoeller
43  * @since 1.1
44  * @see #doExecuteRequest
45  */

46 public abstract class AbstractHttpInvokerRequestExecutor
47         implements HttpInvokerRequestExecutor, BeanClassLoaderAware {
48
49     /**
50      * Default content type: "application/x-java-serialized-object"
51      */

52     public static final String JavaDoc CONTENT_TYPE_SERIALIZED_OBJECT = "application/x-java-serialized-object";
53
54
55     protected static final String JavaDoc HTTP_METHOD_POST = "POST";
56
57     protected static final String JavaDoc HTTP_HEADER_CONTENT_TYPE = "Content-Type";
58
59     protected static final String JavaDoc HTTP_HEADER_CONTENT_LENGTH = "Content-Length";
60
61     protected static final String JavaDoc HTTP_HEADER_ACCEPT_ENCODING = "Accept-Encoding";
62
63     protected static final String JavaDoc HTTP_HEADER_CONTENT_ENCODING = "Content-Encoding";
64
65     protected static final String JavaDoc ENCODING_GZIP = "gzip";
66
67
68     private static final int SERIALIZED_INVOCATION_BYTE_ARRAY_INITIAL_SIZE = 1024;
69
70
71     protected final Log logger = LogFactory.getLog(getClass());
72
73     private String JavaDoc contentType = CONTENT_TYPE_SERIALIZED_OBJECT;
74
75     private boolean acceptGzipEncoding = true;
76
77     private ClassLoader JavaDoc beanClassLoader;
78
79
80     /**
81      * Specify the content type to use for sending HTTP invoker requests.
82      * <p>Default is "application/x-java-serialized-object".
83      */

84     public void setContentType(String JavaDoc contentType) {
85         Assert.notNull(contentType, "'contentType' must not be null");
86         this.contentType = contentType;
87     }
88
89     /**
90      * Return the content type to use for sending HTTP invoker requests.
91      */

92     public String JavaDoc getContentType() {
93         return this.contentType;
94     }
95
96     /**
97      * Set whether to accept GZIP encoding, that is, whether to
98      * send the HTTP "Accept-Encoding" header with "gzip" as value.
99      * <p>Default is "true". Turn this flag off if you do not want
100      * GZIP response compression even if enabled on the HTTP server.
101      */

102     public void setAcceptGzipEncoding(boolean acceptGzipEncoding) {
103         this.acceptGzipEncoding = acceptGzipEncoding;
104     }
105
106     /**
107      * Return whether to accept GZIP encoding, that is, whether to
108      * send the HTTP "Accept-Encoding" header with "gzip" as value.
109      */

110     public boolean isAcceptGzipEncoding() {
111         return this.acceptGzipEncoding;
112     }
113
114     public void setBeanClassLoader(ClassLoader JavaDoc classLoader) {
115         this.beanClassLoader = classLoader;
116     }
117
118     /**
119      * Return the bean ClassLoader that this executor is supposed to use.
120      */

121     protected ClassLoader JavaDoc getBeanClassLoader() {
122         return this.beanClassLoader;
123     }
124
125
126     public final RemoteInvocationResult executeRequest(
127             HttpInvokerClientConfiguration config, RemoteInvocation invocation) throws Exception JavaDoc {
128
129         ByteArrayOutputStream JavaDoc baos = getByteArrayOutputStream(invocation);
130         if (logger.isDebugEnabled()) {
131             logger.debug("Sending HTTP invoker request for service at [" + config.getServiceUrl() +
132                     "], with size " + baos.size());
133         }
134         return doExecuteRequest(config, baos);
135     }
136
137     /**
138      * Serialize the given RemoteInvocation into a ByteArrayOutputStream.
139      * @param invocation the RemoteInvocation object
140      * @return a ByteArrayOutputStream with the serialized RemoteInvocation
141      * @throws IOException if thrown by I/O methods
142      */

143     protected ByteArrayOutputStream JavaDoc getByteArrayOutputStream(RemoteInvocation invocation) throws IOException JavaDoc {
144         ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc(SERIALIZED_INVOCATION_BYTE_ARRAY_INITIAL_SIZE);
145         writeRemoteInvocation(invocation, baos);
146         return baos;
147     }
148
149     /**
150      * Serialize the given RemoteInvocation to the given OutputStream.
151      * <p>The default implementation gives <code>decorateOutputStream</code> a chance
152      * to decorate the stream first (for example, for custom encryption or compression).
153      * Creates an <code>ObjectOutputStream</code> for the final stream and calls
154      * <code>doWriteRemoteInvocation</code> to actually write the object.
155      * <p>Can be overridden for custom serialization of the invocation.
156      * @param invocation the RemoteInvocation object
157      * @param os the OutputStream to write to
158      * @throws IOException if thrown by I/O methods
159      * @see #decorateOutputStream
160      * @see #doWriteRemoteInvocation
161      */

162     protected void writeRemoteInvocation(RemoteInvocation invocation, OutputStream JavaDoc os) throws IOException JavaDoc {
163         ObjectOutputStream JavaDoc oos = new ObjectOutputStream JavaDoc(decorateOutputStream(os));
164         try {
165             doWriteRemoteInvocation(invocation, oos);
166             oos.flush();
167         }
168         finally {
169             oos.close();
170         }
171     }
172
173     /**
174      * Return the OutputStream to use for writing remote invocations,
175      * potentially decorating the given original OutputStream.
176      * <p>The default implementation returns the given stream as-is.
177      * Can be overridden, for example, for custom encryption or compression.
178      * @param os the original OutputStream
179      * @return the potentially decorated OutputStream
180      */

181     protected OutputStream JavaDoc decorateOutputStream(OutputStream JavaDoc os) throws IOException JavaDoc {
182         return os;
183     }
184
185     /**
186      * Perform the actual writing of the given invocation object to the
187      * given ObjectOutputStream.
188      * <p>The default implementation simply calls <code>writeObject</code>.
189      * Can be overridden for serialization of a custom wrapper object rather
190      * than the plain invocation, for example an encryption-aware holder.
191      * @param invocation the RemoteInvocation object
192      * @param oos the ObjectOutputStream to write to
193      * @throws IOException if thrown by I/O methods
194      * @see java.io.ObjectOutputStream#writeObject
195      */

196     protected void doWriteRemoteInvocation(RemoteInvocation invocation, ObjectOutputStream JavaDoc oos) throws IOException JavaDoc {
197         oos.writeObject(invocation);
198     }
199
200
201     /**
202      * Execute a request to send the given serialized remote invocation.
203      * <p>Implementations will usually call <code>readRemoteInvocationResult</code>
204      * to deserialize a returned RemoteInvocationResult object.
205      * @param config the HTTP invoker configuration that specifies the
206      * target service
207      * @param baos the ByteArrayOutputStream that contains the serialized
208      * RemoteInvocation object
209      * @return the RemoteInvocationResult object
210      * @throws IOException if thrown by I/O operations
211      * @throws ClassNotFoundException if thrown during deserialization
212      * @throws Exception in case of general errors
213      * @see #readRemoteInvocationResult(java.io.InputStream, String)
214      */

215     protected abstract RemoteInvocationResult doExecuteRequest(
216             HttpInvokerClientConfiguration config, ByteArrayOutputStream JavaDoc baos)
217             throws Exception JavaDoc;
218
219     /**
220      * Deserialize a RemoteInvocationResult object from the given InputStream.
221      * <p>Gives <code>decorateInputStream</code> a chance to decorate the stream
222      * first (for example, for custom encryption or compression). Creates an
223      * <code>ObjectInputStream</code> via <code>createObjectInputStream</code> and
224      * calls <code>doReadRemoteInvocationResult</code> to actually read the object.
225      * <p>Can be overridden for custom serialization of the invocation.
226      * @param is the InputStream to read from
227      * @param codebaseUrl the codebase URL to load classes from if not found locally
228      * @return the RemoteInvocationResult object
229      * @throws IOException if thrown by I/O methods
230      * @throws ClassNotFoundException if thrown during deserialization
231      * @see #decorateInputStream
232      * @see #createObjectInputStream
233      * @see #doReadRemoteInvocationResult
234      */

235     protected RemoteInvocationResult readRemoteInvocationResult(InputStream JavaDoc is, String JavaDoc codebaseUrl)
236             throws IOException JavaDoc, ClassNotFoundException JavaDoc {
237
238         ObjectInputStream JavaDoc ois = createObjectInputStream(decorateInputStream(is), codebaseUrl);
239         try {
240             return doReadRemoteInvocationResult(ois);
241         }
242         finally {
243             ois.close();
244         }
245     }
246
247     /**
248      * Return the InputStream to use for reading remote invocation results,
249      * potentially decorating the given original InputStream.
250      * <p>The default implementation returns the given stream as-is.
251      * Can be overridden, for example, for custom encryption or compression.
252      * @param is the original InputStream
253      * @return the potentially decorated InputStream
254      */

255     protected InputStream JavaDoc decorateInputStream(InputStream JavaDoc is) throws IOException JavaDoc {
256         return is;
257     }
258
259     /**
260      * Create an ObjectInputStream for the given InputStream and codebase.
261      * The default implementation creates a CodebaseAwareObjectInputStream.
262      * <p>Spring's CodebaseAwareObjectInputStream is not only used for loading
263      * from a specified codebase, but also to explicitly resolve primitive
264      * class names. This is done by the standard ObjectInputStream
265      * on JDK 1.4+, but needs to be done explicitly on JDK 1.3.
266      * @param is the InputStream to read from
267      * @param codebaseUrl the codebase URL to load classes from if not found locally
268      * (can be <code>null</code>)
269      * @return the new ObjectInputStream instance to use
270      * @throws IOException if creation of the ObjectInputStream failed
271      * @see org.springframework.remoting.rmi.CodebaseAwareObjectInputStream
272      */

273     protected ObjectInputStream JavaDoc createObjectInputStream(InputStream JavaDoc is, String JavaDoc codebaseUrl) throws IOException JavaDoc {
274         return new CodebaseAwareObjectInputStream(is, getBeanClassLoader(), codebaseUrl);
275     }
276
277     /**
278      * Perform the actual reading of an invocation object from the
279      * given ObjectInputStream.
280      * <p>The default implementation simply calls <code>readObject</code>.
281      * Can be overridden for deserialization of a custom wrapper object rather
282      * than the plain invocation, for example an encryption-aware holder.
283      * @param ois the ObjectInputStream to read from
284      * @return the RemoteInvocationResult object
285      * @throws IOException if thrown by I/O methods
286      * @see java.io.ObjectOutputStream#writeObject
287      */

288     protected RemoteInvocationResult doReadRemoteInvocationResult(ObjectInputStream JavaDoc ois)
289             throws IOException JavaDoc, ClassNotFoundException JavaDoc {
290
291         Object JavaDoc obj = ois.readObject();
292         if (!(obj instanceof RemoteInvocationResult)) {
293             throw new RemoteException JavaDoc("Deserialized object needs to be assignable to type [" +
294                     RemoteInvocationResult.class.getName() + "]: " + obj);
295         }
296         return (RemoteInvocationResult) obj;
297     }
298
299 }
300
Popular Tags