KickJava   Java API By Example, From Geeks To Geeks.

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


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.IOException JavaDoc;
20 import java.io.InputStream JavaDoc;
21 import java.io.ObjectInputStream JavaDoc;
22 import java.io.ObjectOutputStream JavaDoc;
23 import java.io.OutputStream JavaDoc;
24 import java.rmi.RemoteException JavaDoc;
25
26 import javax.servlet.ServletException JavaDoc;
27 import javax.servlet.http.HttpServletRequest JavaDoc;
28 import javax.servlet.http.HttpServletResponse JavaDoc;
29
30 import org.springframework.beans.factory.InitializingBean;
31 import org.springframework.remoting.rmi.CodebaseAwareObjectInputStream;
32 import org.springframework.remoting.support.RemoteInvocation;
33 import org.springframework.remoting.support.RemoteInvocationBasedExporter;
34 import org.springframework.remoting.support.RemoteInvocationResult;
35 import org.springframework.util.Assert;
36 import org.springframework.web.HttpRequestHandler;
37 import org.springframework.web.util.NestedServletException;
38
39 /**
40  * HTTP request handler that exports the specified service bean as HTTP invoker
41  * service endpoint, accessible via an HTTP invoker proxy.
42  *
43  * <p>Deserializes remote invocation objects and serializes remote invocation
44  * result objects. Uses Java serialization just like RMI, but provides the
45  * same ease of setup as Caucho's HTTP-based Hessian and Burlap protocols.
46  *
47  * <p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b>
48  * It is more powerful and more extensible than Hessian and Burlap, at the
49  * expense of being tied to Java. Nevertheless, it is as easy to set up as
50  * Hessian and Burlap, which is its main advantage compared to RMI.
51  *
52  * @author Juergen Hoeller
53  * @since 1.1
54  * @see HttpInvokerClientInterceptor
55  * @see HttpInvokerProxyFactoryBean
56  * @see org.springframework.remoting.rmi.RmiServiceExporter
57  * @see org.springframework.remoting.caucho.HessianServiceExporter
58  * @see org.springframework.remoting.caucho.BurlapServiceExporter
59  */

60 public class HttpInvokerServiceExporter extends RemoteInvocationBasedExporter
61         implements HttpRequestHandler, InitializingBean {
62
63     /**
64      * Default content type: "application/x-java-serialized-object"
65      */

66     public static final String JavaDoc CONTENT_TYPE_SERIALIZED_OBJECT = "application/x-java-serialized-object";
67
68
69     private String JavaDoc contentType = CONTENT_TYPE_SERIALIZED_OBJECT;
70
71     private Object JavaDoc proxy;
72
73
74     /**
75      * Specify the content type to use for sending HTTP invoker responses.
76      * <p>Default is "application/x-java-serialized-object".
77      */

78     public void setContentType(String JavaDoc contentType) {
79         Assert.notNull(contentType, "'contentType' must not be null");
80         this.contentType = contentType;
81     }
82
83     /**
84      * Return the content type to use for sending HTTP invoker responses.
85      */

86     public String JavaDoc getContentType() {
87         return this.contentType;
88     }
89
90
91     public void afterPropertiesSet() {
92         prepare();
93     }
94
95     /**
96      * Initialize this service exporter.
97      */

98     public void prepare() {
99         this.proxy = getProxyForService();
100     }
101
102
103     /**
104      * Reads a remote invocation from the request, executes it,
105      * and writes the remote invocation result to the response.
106      * @see #readRemoteInvocation(HttpServletRequest)
107      * @see #invokeAndCreateResult(org.springframework.remoting.support.RemoteInvocation, Object)
108      * @see #writeRemoteInvocationResult(HttpServletRequest, HttpServletResponse, RemoteInvocationResult)
109      */

110     public void handleRequest(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
111             throws ServletException JavaDoc, IOException JavaDoc {
112
113         Assert.notNull(this.proxy, "HttpInvokerServiceExporter has not been initialized");
114
115         try {
116             RemoteInvocation invocation = readRemoteInvocation(request);
117             RemoteInvocationResult result = invokeAndCreateResult(invocation, this.proxy);
118             writeRemoteInvocationResult(request, response, result);
119         }
120         catch (ClassNotFoundException JavaDoc ex) {
121             throw new NestedServletException("Class not found during deserialization", ex);
122         }
123     }
124
125
126     /**
127      * Read a RemoteInvocation from the given HTTP request.
128      * <p>Delegates to
129      * {@link #readRemoteInvocation(javax.servlet.http.HttpServletRequest, java.io.InputStream)}
130      * with the
131      * {@link javax.servlet.ServletRequest#getInputStream() servlet request's input stream}.
132      * @param request current HTTP request
133      * @return the RemoteInvocation object
134      * @throws IOException in case of I/O failure
135      * @throws ClassNotFoundException if thrown by deserialization
136      */

137     protected RemoteInvocation readRemoteInvocation(HttpServletRequest JavaDoc request)
138             throws IOException JavaDoc, ClassNotFoundException JavaDoc {
139
140         return readRemoteInvocation(request, request.getInputStream());
141     }
142
143     /**
144      * Deserialize a RemoteInvocation object from the given InputStream.
145      * <p>Gives {@link #decorateInputStream} a chance to decorate the stream
146      * first (for example, for custom encryption or compression). Creates a
147      * {@link org.springframework.remoting.rmi.CodebaseAwareObjectInputStream}
148      * and calls {@link #doReadRemoteInvocation} to actually read the object.
149      * <p>Can be overridden for custom serialization of the invocation.
150      * @param request current HTTP request
151      * @param is the InputStream to read from
152      * @return the RemoteInvocation object
153      * @throws IOException in case of I/O failure
154      * @throws ClassNotFoundException if thrown during deserialization
155      */

156     protected RemoteInvocation readRemoteInvocation(HttpServletRequest JavaDoc request, InputStream JavaDoc is)
157             throws IOException JavaDoc, ClassNotFoundException JavaDoc {
158
159         ObjectInputStream JavaDoc ois = createObjectInputStream(decorateInputStream(request, is));
160         try {
161             return doReadRemoteInvocation(ois);
162         }
163         finally {
164             ois.close();
165         }
166     }
167
168     /**
169      * Return the InputStream to use for reading remote invocations,
170      * potentially decorating the given original InputStream.
171      * <p>The default implementation returns the given stream as-is.
172      * Can be overridden, for example, for custom encryption or compression.
173      * @param request current HTTP request
174      * @param is the original InputStream
175      * @return the potentially decorated InputStream
176      * @throws IOException in case of I/O failure
177      */

178     protected InputStream JavaDoc decorateInputStream(HttpServletRequest JavaDoc request, InputStream JavaDoc is) throws IOException JavaDoc {
179         return is;
180     }
181
182     /**
183      * Create an ObjectInputStream for the given InputStream.
184      * <p>The default implementation creates a Spring
185      * {@link org.springframework.remoting.rmi.CodebaseAwareObjectInputStream}.
186      * <p>Spring's CodebaseAwareObjectInputStream is used to explicitly resolve
187      * primitive class names. This is done by the standard ObjectInputStream
188      * on JDK 1.4+, but needs to be done explicitly on JDK 1.3.
189      * @param is the InputStream to read from
190      * @return the new ObjectInputStream instance to use
191      * @throws IOException if creation of the ObjectInputStream failed
192      */

193     protected ObjectInputStream JavaDoc createObjectInputStream(InputStream JavaDoc is) throws IOException JavaDoc {
194         return new CodebaseAwareObjectInputStream(is, null);
195     }
196
197     /**
198      * Perform the actual reading of an invocation result object from the
199      * given ObjectInputStream.
200      * <p>The default implementation simply calls
201      * {@link java.io.ObjectInputStream#readObject()}.
202      * Can be overridden for deserialization of a custom wrapper object rather
203      * than the plain invocation, for example an encryption-aware holder.
204      * @param ois the ObjectInputStream to read from
205      * @return the RemoteInvocationResult object
206      * @throws IOException in case of I/O failure
207      * @throws ClassNotFoundException if case of a transferred class not
208      * being found in the local ClassLoader
209      */

210     protected RemoteInvocation doReadRemoteInvocation(ObjectInputStream JavaDoc ois)
211             throws IOException JavaDoc, ClassNotFoundException JavaDoc {
212
213         Object JavaDoc obj = ois.readObject();
214         if (!(obj instanceof RemoteInvocation)) {
215             throw new RemoteException JavaDoc("Deserialized object needs to be assignable to type [" +
216                     RemoteInvocation.class.getName() + "]: " + obj);
217         }
218         return (RemoteInvocation) obj;
219     }
220
221
222     /**
223      * Write the given RemoteInvocationResult to the given HTTP response.
224      * @param request current HTTP request
225      * @param response current HTTP response
226      * @param result the RemoteInvocationResult object
227      * @throws IOException in case of I/O failure
228      */

229     protected void writeRemoteInvocationResult(
230             HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, RemoteInvocationResult result)
231             throws IOException JavaDoc {
232
233         response.setContentType(getContentType());
234         writeRemoteInvocationResult(request, response, result, response.getOutputStream());
235     }
236
237     /**
238      * Serialize the given RemoteInvocation to the given OutputStream.
239      * <p>The default implementation gives {@link #decorateOutputStream} a chance
240      * to decorate the stream first (for example, for custom encryption or compression).
241      * Creates an {@link java.io.ObjectOutputStream} for the final stream and calls
242      * {@link #doWriteRemoteInvocationResult} to actually write the object.
243      * <p>Can be overridden for custom serialization of the invocation.
244      * @param request current HTTP request
245      * @param response current HTTP response
246      * @param result the RemoteInvocationResult object
247      * @param os the OutputStream to write to
248      * @throws IOException in case of I/O failure
249      * @see #decorateOutputStream
250      * @see #doWriteRemoteInvocationResult
251      */

252     protected void writeRemoteInvocationResult(
253             HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, RemoteInvocationResult result, OutputStream JavaDoc os)
254             throws IOException JavaDoc {
255
256         ObjectOutputStream JavaDoc oos = createObjectOutputStream(decorateOutputStream(request, response, os));
257         try {
258             doWriteRemoteInvocationResult(result, oos);
259             oos.flush();
260         }
261         finally {
262             oos.close();
263         }
264     }
265
266     /**
267      * Return the OutputStream to use for writing remote invocation results,
268      * potentially decorating the given original OutputStream.
269      * <p>The default implementation returns the given stream as-is.
270      * Can be overridden, for example, for custom encryption or compression.
271      * @param request current HTTP request
272      * @param response current HTTP response
273      * @param os the original OutputStream
274      * @return the potentially decorated OutputStream
275      * @throws IOException in case of I/O failure
276      */

277     protected OutputStream JavaDoc decorateOutputStream(
278             HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, OutputStream JavaDoc os) throws IOException JavaDoc {
279
280         return os;
281     }
282
283     /**
284      * Create an ObjectOutputStream for the given OutputStream.
285      * <p>The default implementation creates a plain
286      * {@link java.io.ObjectOutputStream}.
287      * @param os the OutputStream to write to
288      * @return the new ObjectOutputStream instance to use
289      * @throws IOException if creation of the ObjectOutputStream failed
290      */

291     protected ObjectOutputStream JavaDoc createObjectOutputStream(OutputStream JavaDoc os) throws IOException JavaDoc {
292         return new ObjectOutputStream JavaDoc(os);
293     }
294
295     /**
296      * Perform the actual writing of the given invocation result object
297      * to the given ObjectOutputStream.
298      * <p>The default implementation simply calls
299      * {@link java.io.ObjectOutputStream#writeObject}.
300      * Can be overridden for serialization of a custom wrapper object rather
301      * than the plain invocation, for example an encryption-aware holder.
302      * @param result the RemoteInvocationResult object
303      * @param oos the ObjectOutputStream to write to
304      * @throws IOException if thrown by I/O methods
305      */

306     protected void doWriteRemoteInvocationResult(RemoteInvocationResult result, ObjectOutputStream JavaDoc oos)
307             throws IOException JavaDoc {
308
309         oos.writeObject(result);
310     }
311
312 }
313
Popular Tags