KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > wings > session > WingServlet


1 /*
2  * $Id: WingServlet.java,v 1.8 2005/05/13 15:47:07 blueshift Exp $
3  * Copyright 2000,2005 wingS development team.
4  *
5  * This file is part of wingS (http://www.j-wings.org).
6  *
7  * wingS is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation; either version 2.1
10  * of the License, or (at your option) any later version.
11  *
12  * Please see COPYING for the complete licence.
13  */

14 package org.wings.session;
15
16 import org.apache.commons.logging.Log;
17 import org.apache.commons.logging.LogFactory;
18 import org.wings.RequestURL;
19 import org.wings.externalizer.AbstractExternalizeManager;
20 import org.wings.externalizer.ExternalizedResource;
21 import org.wings.externalizer.SystemExternalizeManager;
22 import org.wings.io.Device;
23 import org.wings.io.ServletDevice;
24
25 import javax.servlet.ServletConfig JavaDoc;
26 import javax.servlet.ServletException JavaDoc;
27 import javax.servlet.http.HttpServlet JavaDoc;
28 import javax.servlet.http.HttpServletRequest JavaDoc;
29 import javax.servlet.http.HttpServletResponse JavaDoc;
30 import javax.servlet.http.HttpSession JavaDoc;
31 import java.io.File JavaDoc;
32 import java.io.IOException JavaDoc;
33 import java.io.UnsupportedEncodingException JavaDoc;
34 import java.util.Enumeration JavaDoc;
35 import java.util.Iterator JavaDoc;
36
37 /**
38  * Central servlet delegating all requests to the according wingS session servlet.
39  *
40  * @author <a HREF="mailto:engels@mercatis.de">Holger Engels</a>
41  * @author <a HREF="mailto:haaf@mercatis.de">Armin Haaf</a>
42  * @version $Revision: 1.8 $
43  */

44 public final class WingServlet
45         extends HttpServlet JavaDoc {
46     private final transient static Log log = LogFactory.getLog(WingServlet.class);
47
48     /**
49      * used to init session servlets
50      */

51     protected ServletConfig JavaDoc servletConfig = null;
52
53     private String JavaDoc lookupName = "SessionServlet";
54
55     public WingServlet() {
56     }
57
58
59     protected void initLookupName(ServletConfig JavaDoc config) {
60         // with specified lookupname it is possible to handle different sessions
61
// for servlet aliases/mappings
62
lookupName = config.getInitParameter("wings.servlet.lookupname");
63
64         if (lookupName == null || lookupName.trim().length() == 0) {
65             lookupName = "SessionServlet:" + config.getInitParameter("wings.mainclass");
66         }
67
68         log.info("use session servlet lookup name " + lookupName);
69     }
70
71     /**
72      * The following init parameters are known by wings.
73      * <p/>
74      * <dl compact>
75      * <dt>externalizer.timeout</dt><dd> - The time, externalized objects
76      * are kept, before they are removed</dd>
77      * <p/>
78      * <dt>content.maxlength</dt><dd> - Maximum content lengt for form posts.
79      * Remember to increase this, if you make use of the SFileChooser
80      * component</dd>
81      * <p/>
82      * <dt>filechooser.uploaddir</dt><dd> - The directory, where uploaded
83      * files ar stored temporarily</dd>
84      * </dl>
85      * <p/>
86      * <dt>wings.servlet.lookupname</dt><dd> - The name the wings sessions of
87      * this servlet instance are stored in the servlet session hashtable</dd>
88      * </dl>
89      *
90      * @throws ServletException
91      */

92     public final void init(ServletConfig JavaDoc config) throws ServletException JavaDoc {
93         super.init(config);
94         servletConfig = config;
95
96         if (log.isInfoEnabled()) {
97             log.info("init-params:");
98             for (Enumeration JavaDoc en = config.getInitParameterNames(); en.hasMoreElements();) {
99                 String JavaDoc param = (String JavaDoc) en.nextElement();
100                 log.info(param + " = " + config.getInitParameter(param));
101             }
102         }
103
104         initLookupName(config);
105     }
106
107     /**
108      * returns the last modification of an externalized resource to allow the
109      * browser to cache it.
110      */

111     protected long getLastModified(HttpServletRequest JavaDoc request) {
112         AbstractExternalizeManager extMgr;
113         try {
114             extMgr = getExternalizeManager(request);
115         } catch (Exception JavaDoc e) {
116             return System.currentTimeMillis();
117         }
118         String JavaDoc pathInfo = request.getPathInfo();
119         if (extMgr != null && pathInfo != null && pathInfo.length() > 1) {
120             String JavaDoc identifier = pathInfo.substring(1);
121             ExternalizedResource info = extMgr.getExternalizedResource(identifier);
122             if (info != null) {
123                 //System.err.println(" **>" + info.getLastModified());
124
return info.getLastModified();
125             }
126         }
127         return -1;
128     }
129
130     /**
131      * Parse POST request with <code>MultipartRequest</code> and passes to <code>doGet()</code>
132      */

133     public final void doPost(HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc res)
134             throws ServletException JavaDoc, IOException JavaDoc {
135         SessionServlet sessionServlet = getSessionServlet(req, res, true);
136
137         if (log.isDebugEnabled())
138             log.debug((sessionServlet != null) ?
139                     lookupName :
140                     "no session yet ..");
141
142         // Wrap with MultipartRequest which can handle multipart/form-data
143
// (file - upload), otherwise behaves like normal HttpServletRequest
144
try {
145             int maxContentLength = sessionServlet.getSession().getMaxContentLength();
146             req = new MultipartRequest(req, maxContentLength * 1024);
147         } catch (Exception JavaDoc e) {
148             log.fatal(null, e);
149         }
150
151         if (log.isDebugEnabled()) {
152             if (req instanceof MultipartRequest) {
153                 MultipartRequest multi = (MultipartRequest) req;
154                 log.debug("Files:");
155                 Iterator JavaDoc files = multi.getFileNames();
156                 while (files.hasNext()) {
157                     String JavaDoc name = (String JavaDoc) files.next();
158                     String JavaDoc filename = multi.getFileName(name);
159                     String JavaDoc type = multi.getContentType(name);
160                     File JavaDoc f = multi.getFile(name);
161                     log.debug("name: " + name);
162                     log.debug("filename: " + filename);
163                     log.debug("type: " + type);
164                     if (f != null) {
165                         log.debug("f.toString(): " + f.toString());
166                         log.debug("f.getDescription(): " + f.getName());
167                         log.debug("f.exists(): " + f.exists());
168                         log.debug("f.length(): " + f.length());
169                         log.debug("\n");
170                     }
171                 }
172             }
173         }
174
175         doGet(req, res);
176     }
177
178     private final SessionServlet newSession(HttpServletRequest JavaDoc request,
179                                             HttpServletResponse JavaDoc response)
180             throws ServletException JavaDoc {
181         long timestamp = System.currentTimeMillis();
182         try {
183             log.debug("new session");
184
185             SessionServlet sessionServlet = new SessionServlet();
186             sessionServlet.init(servletConfig, request, response);
187
188             Session session = sessionServlet.getSession();
189             /* the request URL is needed already in the setup-phase. Note,
190              * that at this point, the URL will always be encoded, since
191              * we (or better: the servlet engine) does not know yet, if setting
192              * a cookie will be successful (it has to await the response).
193              * Subsequent requests might decide, _not_ to encode the sessionid
194              * in the URL (see SessionServlet::doGet()) -hen
195              */

196             RequestURL requestURL = new RequestURL("", SessionServlet.getSessionEncoding(response));
197
198             session.setProperty("request.url", requestURL);
199
200             sessionServlet.setParent(this);
201
202             log.debug("time to create a new session " + (System.currentTimeMillis() - timestamp));
203             return sessionServlet;
204         } catch (Exception JavaDoc e) {
205             log.fatal("Error on creating new wingS session", e);
206             throw new ServletException JavaDoc(e);
207         }
208     }
209
210     public final SessionServlet getSessionServlet(HttpServletRequest JavaDoc request,
211                                                   HttpServletResponse JavaDoc response,
212                                                   boolean createSessionServlet)
213             throws ServletException JavaDoc {
214         HttpSession JavaDoc httpSession = request.getSession(true);
215
216         // it should be enough to synchronize on the http session object...
217
synchronized (httpSession) {
218             SessionServlet sessionServlet = null;
219
220             if (httpSession != null) {
221                 sessionServlet = (SessionServlet) httpSession.getAttribute(lookupName);
222             }
223
224             /*
225              * we are only interested in a new session, if the response is
226              * not null. If it is null, then we just called getSessionServlet()
227              * for lookup purposes and are satisfied, if we don't get anything.
228              */

229             if (sessionServlet == null && createSessionServlet) {
230                 log.info("no session servlet, create new one");
231                 sessionServlet = newSession(request, response);
232                 httpSession.setAttribute(lookupName, sessionServlet);
233             }
234
235
236             if (log.isDebugEnabled()) {
237                 log.debug("session id " + request.getRequestedSessionId());
238                 log.debug("session from cookie " + request.isRequestedSessionIdFromCookie());
239                 log.debug("session from url " + request.isRequestedSessionIdFromURL());
240                 log.debug("session valid " + request.isRequestedSessionIdValid());
241                 log.debug("session created at " +
242                         new java.util.Date JavaDoc(httpSession.getCreationTime()));
243                 log.debug("session httpsession id " + httpSession.getId());
244                 log.debug("session httpsession new " + httpSession.isNew());
245                 log.debug("session last accessed at " +
246                         new java.util.Date JavaDoc(httpSession.getLastAccessedTime()));
247                 log.debug("session max inactive interval " +
248                         httpSession.getMaxInactiveInterval());
249                 log.debug("session contains wings session " +
250                         (httpSession.getAttribute(lookupName) != null));
251             }
252
253             sessionServlet.getSession().getExternalizeManager().setResponse(response);
254
255             /* Handling of the requests character encoding.
256              * --------------------------------------------
257              * The following block is needed for a correct handling of
258              * non-ISO-8859-1 data:
259              *
260              * Using LocaleCharacterSet and/or charset.properties we can
261              * advise the client to use i.e. UTF-8 as character encoding.
262              * Once told the browser consequently also encodes his requests
263              * in the choosen characterset of the sings session. This is
264              * achieved by adding the HTML code
265              * <meta http-equiv="Content-Type" content="text/html;charset="<charset>">
266              * to the generated pages.
267              *
268              * If the user hasn't overridden the encoding in their browser,
269              * then all form data (e.g. mueller) is submitted with data encoded
270              * like m%C3%BCller because byte pair C3 BC is how the german
271              * u-umlaut is represented in UTF-8. If the form is
272              * iso-8859-1 encoded then you get m%FCller, because byte FC is
273              * how it is presented in iso-8859-1.
274              *
275              * So the browser behaves correctly by sending his form input
276              * correctly encoded in the advised character encoding. The issue
277              * is that the servlet container is typically unable to determine
278              * the correct encoding of this form data. By proposal the browser
279              * should als declare the used character encoding for his data.
280              * But actual browsers omit this information and hence the servlet
281              * container is unable to guess the right encoding (Tomcat actually
282              * thenalways guesses ISO 8859-1). This results in totally
283              * scrumbled up data for all non ISO-8859-1 character encodings.
284              * With the block below we tell the servlet container about the
285              * character encoding we expect in the browsers request and hence
286              * the servlet container can do the correct decoding.
287              * This has to be done at very first, otherwise the servlet
288              * container will ignore this setting.
289              */

290              
291             // TODO: Actually the whole character encoding is depending
292
if ((request.getCharacterEncoding() == null)) { // was servlet container able to identify encoding?
293
try {
294                     String JavaDoc sessionCharacterEncoding = sessionServlet.getSession().getCharacterEncoding();
295                     // We know better about the used character encoding than tomcat
296
log.debug("Advising servlet container to interpret request as " + sessionCharacterEncoding);
297                     request.setCharacterEncoding(sessionCharacterEncoding);
298                 } catch (UnsupportedEncodingException JavaDoc e) {
299                     log.warn("Problem on applying current session character encoding", e);
300                 }
301             }
302
303             return sessionServlet;
304         }
305     }
306
307     /** -- externalization -- **/
308
309     /**
310      * returns, whether this request is to serve an externalize request.
311      */

312     protected boolean isSystemExternalizeRequest(HttpServletRequest JavaDoc request) {
313         String JavaDoc pathInfo = request.getPathInfo();
314         return (pathInfo != null
315                 && pathInfo.length() > 1
316                 && pathInfo.startsWith("/-"));
317     }
318
319
320     protected AbstractExternalizeManager getExternalizeManager(HttpServletRequest JavaDoc req)
321             throws ServletException JavaDoc {
322         if (isSystemExternalizeRequest(req)) {
323             return SystemExternalizeManager.getSharedInstance();
324         } else {
325             SessionServlet sessionServlet = getSessionServlet(req, null, false);
326             if (sessionServlet == null)
327                 return null;
328             return sessionServlet.getSession().getExternalizeManager();
329         }
330     }
331
332     public final void doGet(HttpServletRequest JavaDoc req,
333                             HttpServletResponse JavaDoc response)
334             throws ServletException JavaDoc, IOException JavaDoc {
335
336         try {
337             /*
338              * make sure, that our context ends with '/'. Otherwise redirect
339              * to the same location with appended slash.
340              *
341              * We need a '/' at the
342              * end of the servlet, so that relative requests work. Relative
343              * requests are either externalization requests, providing the
344              * required resource name in the path info (like 'abc_121.gif')
345              * or 'normal' requests which are just an empty URL with the
346              * request parameter (like '?12_22=121').
347              * The browser assembles the request URL from the current context
348              * (the 'directory' it assumes it is in) plus the relative URL.
349              * Thus emitted URLs are as short as possible and thus the
350              * generated page size.
351              */

352             String JavaDoc pathInfo = req.getPathInfo();
353
354             if (pathInfo == null || pathInfo.length() == 0) {
355                 StringBuffer JavaDoc pathUrl = req.getRequestURL();
356                 pathUrl.append('/');
357                 if (req.getQueryString() != null) {
358                     pathUrl.append('?').append(req.getQueryString());
359                 }
360
361                 log.debug("redirect to " + pathUrl.toString());
362                 response.sendRedirect(pathUrl.toString());
363                 return;
364             }
365
366
367             /*
368              * we either have a request for the system externalizer
369              * (if there is something in the path info, that starts with '-')
370              * or just a normal request to this servlet.
371              */

372             if (isSystemExternalizeRequest(req)) {
373                 String JavaDoc identifier = pathInfo.substring(1);
374                 AbstractExternalizeManager extManager =
375                         SystemExternalizeManager.getSharedInstance();
376                 ExternalizedResource extInfo = extManager
377                         .getExternalizedResource(identifier);
378                 if (extInfo != null) {
379                     extManager.deliver(extInfo, response,
380                             createOutputDevice(req, response,
381                                     extInfo));
382                 }
383                 return;
384             }
385
386             log.debug("session servlet");
387
388             SessionServlet sessionServlet = getSessionServlet(req, response, true);
389
390             sessionServlet.doGet(req, response);
391         } catch (ServletException JavaDoc e) {
392             log.fatal("doGet", e);
393             throw e;
394         } catch (Throwable JavaDoc e) {
395             log.fatal("doGet", e);
396             throw new ServletException JavaDoc(e);
397         }
398     }
399
400     /**
401      * create a Device that is used to deliver the content, that is
402      * not session specific, i.e. that is delivered by the SystemExternalizer.
403      * The default
404      * implementation just creates a ServletDevice. You can override this
405      * method to decide yourself what happens to the output. You might, for
406      * instance, write some device, that logs the output for debugging
407      * purposes, or one that creates a gziped output stream to transfer
408      * data more efficiently. You get the request and response as well as
409      * the ExternalizedResource to decide, what kind of device you want to create.
410      * You can rely on the fact, that extInfo is not null.
411      * Further, you can rely on the fact, that noting has been written yet
412      * to the output, so that you can set you own set of Headers.
413      *
414      * @param request the HttpServletRequest that is answered
415      * @param response the HttpServletResponse.
416      * @param extInfo the externalized info of the resource about to be
417      * delivered.
418      */

419     protected Device createOutputDevice(HttpServletRequest JavaDoc request,
420                                         HttpServletResponse JavaDoc response,
421                                         ExternalizedResource extInfo)
422             throws IOException JavaDoc {
423         return new ServletDevice(response.getOutputStream());
424     }
425 }
426
427
428
Popular Tags