KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > data > DataSource


1 /****************************************************************************
2  * DataSource.java
3  * ****************************************************************************/

4
5 /* J_LZ_COPYRIGHT_BEGIN *******************************************************
6 * Copyright 2001-2004 Laszlo Systems, Inc. All Rights Reserved. *
7 * Use is subject to license terms. *
8 * J_LZ_COPYRIGHT_END *********************************************************/

9
10 package org.openlaszlo.data;
11
12 import java.io.*;
13 import java.net.MalformedURLException JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.StringTokenizer JavaDoc;
16 import javax.servlet.http.HttpServletRequest JavaDoc;
17 import javax.servlet.http.HttpServletResponse JavaDoc;
18 import org.apache.commons.httpclient.URI;
19 import org.apache.commons.httpclient.URIException;
20 import org.apache.log4j.Logger;
21 import org.openlaszlo.utils.LZHttpUtils;
22 import org.openlaszlo.utils.FileUtils;
23 import org.openlaszlo.media.MimeType;
24
25 /**
26  * Base class for server side LZX data/media sources.
27  */

28 abstract public class DataSource
29 {
30     private static Logger mLogger = Logger.getLogger(DataSource.class);
31
32     /**
33      * Get unique name of this data source.
34      *
35      * @return unique name of this data source.
36      */

37     public abstract String JavaDoc name();
38
39     /**
40      * Get the data for this request.
41      *
42      * @return the data for this request.
43      * @param app absolute pathnane to app file.
44      * @param req request in progress.
45      * @param res response object.
46      * @param lastModifiedTime this is the timestamp on the currently cached
47      * item; this time can be used as the datasource sees fit (or ignored) in
48      * constructing the results. If the value is -1, assume there is no
49      * currently cached item.
50      *
51      * @throws DataSourceException if there was a problem with the data source.
52      * @throws IOException if there was a problem retrieving the data.
53      * @throws InterrupedIOException if there was a timeout retrieving the data.
54      */

55     public abstract Data getData(String JavaDoc app, HttpServletRequest JavaDoc req,
56                                  HttpServletResponse JavaDoc res, long lastModifiedTime)
57         throws InterruptedIOException, IOException, DataSourceException;
58
59
60     /**
61      * Determine the datasource from the incoming request,
62      * get the data, convert it to SWF, and write it out
63      * to the given response.
64      *
65      * @param app absolute path name to app requesting data
66      * @param req request
67      * @param res response
68      * @param converter converter to use
69      * @throws DataSourceException if the data source encounters an error
70      * @throws ConversionException if the conversion to SWF returns an error
71      * @throws IOException if there is an IO error
72      */

73     final public void getAsSWF(
74             String JavaDoc app,
75             HttpServletRequest JavaDoc req,
76             HttpServletResponse JavaDoc res,
77             Converter converter)
78         throws DataSourceException, ConversionException, IOException {
79
80         Data data = null;
81         InputStream input = null;
82         OutputStream output = null;
83         long size = -1;
84         long since = -1;
85
86         // Check to see if client side caching is on
87
boolean doClientCache = isClientCacheable(req);
88         if (doClientCache) {
89             String JavaDoc hdr = req.getHeader(LZHttpUtils.IF_MODIFIED_SINCE);
90             if (hdr != null) {
91                mLogger.debug("req last modified time: " + hdr);
92                since = LZHttpUtils.getDate(hdr);
93             }
94         }
95
96         mLogger.info("requesting URL: '" + DataSource.getURL(req) + "'");
97         try {
98             data = getData(app, req, res, since);
99     
100             if (data.notModified()) {
101                 mLogger.info("NOT_MODIFIED");
102                 res.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
103                 return;
104             }
105
106             mLogger.debug("got data");
107
108             if (!data.getMimeType().equals(MimeType.SWF)) {
109
110                 input = converter.convertToSWF(data, req, res);
111                 size = input.available();
112                 mLogger.debug("converted to " + size + " bytes of SWF");
113                 // FIXME: [2003-09-22 bloch] input.available not realiable
114

115                 String JavaDoc enc = converter.chooseEncoding(req);
116                 if (enc != null && !enc.equals("")) {
117                     input = converter.encode(req, input, enc);
118                     res.setHeader(LZHttpUtils.CONTENT_ENCODING, enc);
119                     size = input.available();
120                 }
121
122             } else {
123                 mLogger.debug("remote content was SWF");
124                 input = data.getInputStream();
125                 size = data.size();
126             }
127
128             if (size != -1) {
129                 mLogger.debug("setting content length: " + size);
130                 res.setContentLength((int)size);
131             }
132
133             if (doClientCache) {
134                 long t = data.lastModified();
135                 if (t != -1) {
136                     res.setDateHeader(LZHttpUtils.LAST_MODIFIED, t);
137                 }
138             } else {
139                 LZHttpUtils.noStore(res);
140             }
141
142             try {
143                 output = res.getOutputStream();
144                 long n = FileUtils.sendToStream(input, output);
145                 mLogger.info(n + " bytes sent");
146             } catch (FileUtils.StreamWritingException e) {
147                 mLogger.warn("StreamWritingException while responding: " +
148                         e.getMessage());
149             }
150
151         } finally {
152             if (data != null) {
153                 data.release();
154             }
155             FileUtils.close(output);
156             FileUtils.close(input);
157         }
158     }
159
160     /**
161      * Determine the datasource from the incoming request,
162      * get the data, and write it out
163      * to the given response.
164      *
165      * @param app pathname to app on disk
166      * @param req http request
167      * @param res http response
168      * @throws DataSourceException if the data source encounters an error
169      * @throws IOException if there is an IO error
170      */

171     final public void get(
172             String JavaDoc app,
173             HttpServletRequest JavaDoc req,
174             HttpServletResponse JavaDoc res)
175         throws DataSourceException, IOException {
176
177         Data data = null;
178         InputStream input = null;
179         OutputStream output = null;
180         long size = -1;
181
182         mLogger.info("requesting URL: '" + DataSource.getURL(req) + "'");
183
184         try {
185
186             data = getData(app, req, res, -1);
187     
188             input = data.getInputStream();
189             // FIXME: [2003-04-26 bloch] Reenable content-length header at some point.
190
// Client will sometimes bail in this situation:
191
// 1) set content length and bit client interrupts/closes socket before
192
// all content comes down.
193
// 2) next time the urls is hit, the client requests, server responds,
194
// but nothing shows in the browser. This seems to happen only
195
// when the content is coming from
196
// size = data.size();
197
size = -1;
198
199             if (size != -1) {
200                 mLogger.debug("setting content length: " + size);
201                 res.setContentLength((int)size);
202             }
203
204             // Hopefully back end tells the truth
205
res.setContentType(data.getMimeType());
206
207             output = res.getOutputStream();
208             long n = FileUtils.send(input, output);
209             mLogger.info(n + " bytes sent");
210
211         } finally {
212             if (data != null) {
213                 data.release();
214             }
215             FileUtils.close(output);
216             FileUtils.close(input);
217         }
218     }
219
220
221     /**
222      * Return true if the request is marked cacheable on the client
223      */

224     final static public boolean isClientCacheable(HttpServletRequest JavaDoc req) {
225         String JavaDoc str = req.getParameter("ccache");
226         return (str != null && str.equals("true"));
227     }
228
229
230     /**
231      * Get the URL query paramter for this request.
232      *
233      * @param req servlet request object to retrieve URL parameter.
234      * @return the 'URL' for the request.
235      * @throws MalformedURLException if the url parameter is missing from the request.
236      */

237     final static public String JavaDoc getURL(HttpServletRequest JavaDoc req) throws
238         MalformedURLException JavaDoc {
239
240         String JavaDoc surl = req.getParameter("url");
241         if (surl == null) {
242             throw new MalformedURLException JavaDoc("'url' parameter missing from request");
243         }
244         
245         // "file:" is no longer supported, it is a security hole, make it into an "http"
246
// URL which points to the designated file.
247
if (surl.startsWith("file:")) {
248             String JavaDoc protocol = (req.isSecure()?"https":"http");
249             String JavaDoc host = req.getServerName();
250             int port = req.getServerPort();
251             String JavaDoc cp = req.getContextPath();
252
253             // go past the "file:" prefix
254
String JavaDoc fpath = surl.substring(5);
255             String JavaDoc uri = req.getRequestURI();
256             int floc = uri.lastIndexOf("/");
257
258             // for original url of "file:foo.xml, this constructs
259
// http://host:protocol/servlet-path/app-path/foo.xml
260
surl = protocol + "://" + host + ":" + port
261                 + uri.substring(0,floc) + "/" + fpath;
262
263         }
264
265
266         mLogger.debug("'url' is " + surl);
267         return LZHttpUtils.modifyWEBAPP(req, surl);
268     }
269
270
271     /**
272      * Utility function to get a hash map of query parameters from
273      * an url string.
274      *
275      * @param url string containing an URL to parse query parameters.
276      * @return hash map of query parameters, or an empty hash map if no query
277      * parameters exist.
278      */

279     final static public HashMap JavaDoc getQueryString(String JavaDoc url)
280     {
281         HashMap JavaDoc map = new HashMap JavaDoc();
282         try {
283             URI uri = new URI(url.toCharArray());
284             String JavaDoc query = uri.getQuery();
285             if (query != null) {
286                 StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(query, "&");
287                 while (st.hasMoreTokens()) {
288                     String JavaDoc param = st.nextToken();
289                     int i = param.indexOf("=");
290                     if (i != -1) {
291                         String JavaDoc k = param.substring(0, i);
292                         String JavaDoc v = param.substring(i+1, param.length());
293                         map.put(k, v);
294                     }
295                 }
296             }
297         } catch (URIException e) {
298             mLogger.debug("URIException: " + e.getMessage());
299         }
300         return map;
301     }
302 }
303
Popular Tags