001: /*
002: * Copyright 2000,2005 wingS development team.
003: *
004: * This file is part of wingS (http://wingsframework.org).
005: *
006: * wingS is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU Lesser General Public License
008: * as published by the Free Software Foundation; either version 2.1
009: * of the License, or (at your option) any later version.
010: *
011: * Please see COPYING for the complete licence.
012: */
013: package org.wings.session;
014:
015: import org.apache.commons.logging.Log;
016: import org.apache.commons.logging.LogFactory;
017: import org.wings.*;
018: import org.wings.script.JavaScriptListener;
019: import org.wings.event.ExitVetoException;
020: import org.wings.event.SRequestEvent;
021: import org.wings.externalizer.ExternalizeManager;
022: import org.wings.externalizer.ExternalizedResource;
023: import org.wings.io.*;
024: import org.wings.portlet.Const;
025: import org.wings.portlet.PortletParameterCodec;
026: import org.wings.resource.*;
027: import org.wings.util.SStringBuilder;
028:
029: import javax.portlet.PortletURL;
030: import javax.portlet.RenderRequest;
031: import javax.portlet.RenderResponse;
032: import javax.servlet.ServletConfig;
033: import javax.servlet.ServletContext;
034: import javax.servlet.ServletException;
035: import javax.servlet.ServletOutputStream;
036: import javax.servlet.http.*;
037:
038: import java.io.IOException;
039: import java.util.Enumeration;
040: import java.util.HashMap;
041: import java.util.Iterator;
042: import java.util.Locale;
043: import java.util.Arrays;
044: import java.util.Map;
045: import java.util.Set;
046:
047: /**
048: * The servlet engine creates for each user a new HttpSession. This
049: * HttpSession can be accessed by all Serlvets running in the engine. A
050: * WingServlet creates one wings SessionServlet per HTTPSession and stores
051: * it in its context.
052: * <p>As the SessionServlets acts as Wrapper for the WingsServlet, you can
053: * access from there as used the ServletContext and the HttpSession.
054: * Additionally the SessionServlet containts also the wingS-Session with
055: * all important services and the superordinated SFrame. To this SFrame all
056: * wings-Components and hence the complete application state is attached.
057: * The developer can access from any place via the SessionManager a
058: * reference to the wingS-Session. Additionally the SessionServlet
059: * provides access to the all containing HttpSession.
060: *
061: * @author <a href="mailto:haaf@mercatis.de">Armin Haaf</a>
062: * @author <a href="mailto:marc.musch@mercatis.com">Marc Musch</a>
063: */
064: final class PortletSessionServlet extends HttpServlet implements
065: HttpSessionBindingListener {
066: private final transient static Log log = LogFactory
067: .getLog(PortletSessionServlet.class);
068:
069: /**
070: * The parent {@link PortletWingServlet}
071: */
072: protected transient HttpServlet parent = this ;
073:
074: /**
075: * The session.
076: */
077: private transient/* --- ATTENTION! This disable session serialization! */ExtendedSession session;
078:
079: private boolean firstRequest = true;
080:
081: /** Refer to comment in {@link #doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)} */
082: private String exitSessionWorkaround;
083:
084: /**
085: * Default constructor.
086: */
087: protected PortletSessionServlet() {
088: }
089:
090: /**
091: * Sets the parent servlet contianint this wings session
092: * servlet (WingsServlet, delegating its requests to the SessionServlet).
093: */
094: protected final void setParent(HttpServlet p) {
095: if (p != null)
096: parent = p;
097: }
098:
099: public final Session getSession() {
100: return session;
101: }
102:
103: /**
104: * Overrides the session set for setLocaleFromHeader by a request parameter.
105: * Hence you can force the wings session to adopt the clients Locale.
106: */
107: public final void setLocaleFromHeader(String[] args) {
108: if (args == null)
109: return;
110:
111: for (int i = 0; i < args.length; i++) {
112: try {
113: getSession().setLocaleFromHeader(
114: Boolean.valueOf(args[i]).booleanValue());
115: } catch (Exception e) {
116: log.error("setLocaleFromHeader", e);
117: }
118: }
119: }
120:
121: /**
122: * The Locale of the current wings session servlet is determined by
123: * the locale transmitted by the browser. The request parameter
124: * <PRE>LocaleFromHeader</PRE> can override the behaviour
125: * of a wings session servlet to adopt the clients browsers Locale.
126: *
127: * @param req The request to determine the local from.
128: */
129: protected final void handleLocale(HttpServletRequest req) {
130: setLocaleFromHeader(req.getParameterValues("LocaleFromHeader"));
131:
132: if (getSession().getLocaleFromHeader())
133: getSession().determineLocale();
134: }
135:
136: // jetzt kommen alle Servlet Methoden, die an den parent deligiert
137: // werden
138:
139: public ServletContext getServletContext() {
140: if (parent != this )
141: return parent.getServletContext();
142: else
143: return super .getServletContext();
144: }
145:
146: public String getInitParameter(String name) {
147: if (parent != this )
148: return parent.getInitParameter(name);
149: else
150: return super .getInitParameter(name);
151: }
152:
153: public Enumeration getInitParameterNames() {
154: if (parent != this )
155: return parent.getInitParameterNames();
156: else
157: return super .getInitParameterNames();
158: }
159:
160: /**
161: * Delegates log messages to the according WingsServlet or alternativly
162: * to the HttpServlet logger.
163: *
164: * @param msg The logmessage
165: */
166: public void log(String msg) {
167: if (parent != this )
168: parent.log(msg);
169: else
170: super .log(msg);
171: }
172:
173: public String getServletInfo() {
174: if (parent != this )
175: return parent.getServletInfo();
176: else
177: return super .getServletInfo();
178: }
179:
180: public ServletConfig getServletConfig() {
181: if (parent != this )
182: return parent.getServletConfig();
183: else
184: return super .getServletConfig();
185: }
186:
187: // bis hierhin
188:
189: /**
190: * init
191: */
192: public final void init(ServletConfig config,
193: HttpServletRequest request, HttpServletResponse response)
194: throws ServletException {
195: try {
196: // wingS-Portlet-Bridge: changed form Session to PortletSession
197: session = new ExtendedSession();
198: SessionManager.setSession(session);
199:
200: // set request.url in session, if used in constructor of wings main classs
201: //if (request.isRequestedSessionIdValid()) {
202: // get the RenderResponse out of the request
203: RenderResponse renderResponse = (RenderResponse) request
204: .getAttribute(Const.REQUEST_ATTR_RENDER_RESPONSE);
205: if (renderResponse == null) {
206: log
207: .error("WingS-Portlet-Bridge: cant get the request attribute "
208: + Const.REQUEST_ATTR_RENDER_RESPONSE);
209: }
210: PortletURL actionURL = renderResponse.createActionURL();
211: // this will fire an event, if the encoding has changed ..
212: session.setProperty("request.url", new PortletRequestURL(
213: actionURL.toString(), response.encodeURL(actionURL
214: .toString())));
215: log
216: .debug("WingS-Portlet-Bridge: created while init PortletRequestURL "
217: + actionURL.toString());
218: session.setProperty(
219: Const.WINGS_SESSION_PROPERTY_RENDER_RESPONSE,
220: renderResponse);
221:
222: // get the RenderRequest
223: RenderRequest renderRequest = (RenderRequest) request
224: .getAttribute(Const.REQUEST_ATTR_RENDER_REQUEST);
225: if (renderRequest == null) {
226: log
227: .error("WingS-Portlet-Bridge: cant get the request attribute "
228: + Const.REQUEST_ATTR_RENDER_REQUEST);
229: }
230: session.setProperty(
231: Const.WINGS_SESSION_PROPERTY_RENDER_REQUEST,
232: renderRequest);
233:
234: //}
235:
236: session.init(config, request, response);
237:
238: try {
239: // WingS-Portlet-Bridge: load of class for current mode
240: String mainClassName = (String) request
241: .getAttribute(Const.REQUEST_ATTR_WINGS_CLASS);
242: // String mainClassName = config.getInitParameter("wings.mainclass");
243: log.info("WingS-Portlet-Bridge: loaded mainclass "
244: + mainClassName + " for PortletSessionServlet");
245: Class mainClass = null;
246: try {
247: mainClass = Class.forName(mainClassName, true,
248: Thread.currentThread()
249: .getContextClassLoader());
250: } catch (ClassNotFoundException e) {
251: // fallback, in case the servlet container fails to set the
252: // context class loader.
253: mainClass = Class.forName(mainClassName);
254: }
255: mainClass.newInstance();
256: } catch (Exception ex) {
257: log
258: .fatal(
259: "could not load wings.mainclass: "
260: + request
261: .getAttribute(Const.REQUEST_ATTR_WINGS_CLASS),
262: ex);
263: throw new ServletException(ex);
264: }
265: } finally {
266: // The session was set by the constructor. After init we
267: // expect that only doPost/doGet is called, which set the
268: // session also. So remove it here.
269: SessionManager.removeSession();
270: }
271: }
272:
273: /**
274: * this method references to
275: * {@link #doGet(HttpServletRequest, HttpServletResponse)}
276: */
277: public final void doPost(HttpServletRequest req,
278: HttpServletResponse res) throws IOException {
279: //value chosen to limit denial of service
280: if (req.getContentLength() > getSession().getMaxContentLength() * 1024) {
281: res.setContentType("text/html");
282: ServletOutputStream out = res.getOutputStream();
283: // WingS-Portlet-Bridge: removed unsupported tags
284: out.println("<div><h1>Error - content length > "
285: + getSession().getMaxContentLength() + "k");
286: out.println("</h1></div>");
287: } else {
288: doGet(req, res);
289: }
290: // sollte man den obigen Block nicht durch folgende Zeile ersetzen?
291: //throw new RuntimeException("this method must never be called!");
292: // bsc: Wieso?
293: }
294:
295: /**
296: * Verarbeitet Informationen vom Browser:
297: * <UL>
298: * <LI> setzt Locale
299: * <LI> Dispatch Get Parameter
300: * <LI> feuert Form Events
301: * </UL>
302: * Ist synchronized, damit nur ein Frame gleichzeitig bearbeitet
303: * werden kann.
304: */
305: public final synchronized void doGet(HttpServletRequest req,
306: HttpServletResponse response) {
307: // Special case: You double clicked i.e. a "logout button"
308: // First request arrives, second is on hold. First invalidates session and sends redirect as response,
309: // but browser ignores and expects response in second request. But second request has longer a valid session.
310: if (session == null) {
311: try {
312: response
313: .sendRedirect(exitSessionWorkaround != null ? exitSessionWorkaround
314: : "");
315: return;
316: } catch (IOException e) {
317: log
318: .info("Session exit workaround failed to to IOException (triple click?)");
319: }
320: }
321:
322: SessionManager.setSession(session);
323: session.setServletRequest(req);
324: session.setServletResponse(response);
325:
326: session.fireRequestEvent(SRequestEvent.REQUEST_START);
327:
328: // in case, the previous thread did not clean up.
329: SForm.clearArmedComponents();
330:
331: Device outputDevice = null;
332:
333: ReloadManager reloadManager = session.getReloadManager();
334:
335: try {
336: /*
337: * The tomcat 3.x has a bug, in that it does not encode the URL
338: * sometimes. It does so, when there is a cookie, containing some
339: * tomcat sessionid but that is invalid (because, for instance,
340: * we restarted the tomcat in-between).
341: * [I can't think of this being the correct behaviour, so I assume
342: * it is a bug. ]
343: *
344: * So we have to workaround this here: if we actually got the
345: * session id from a cookie, but it is not valid, we don't do
346: * the encodeURL() here: we just leave the requestURL as it is
347: * in the properties .. and this is url-encoded, since
348: * we had set it up in the very beginning of this session
349: * with URL-encoding on (see WingServlet::newSession()).
350: *
351: * Vice versa: if the requestedSessionId is valid, then we can
352: * do the encoding (which then does URL-encoding or not, depending
353: * whether the servlet engine detected a cookie).
354: * (hen)
355: */
356: RequestURL portletRequestURL = null;
357: // get the renderResponse
358: RenderResponse renderResponse = (RenderResponse) req
359: .getAttribute(Const.REQUEST_ATTR_RENDER_RESPONSE);
360: if (renderResponse == null) {
361: log
362: .error("WingS-Portlet-Bridge: cant get the request attribute "
363: + Const.REQUEST_ATTR_RENDER_RESPONSE);
364: }
365: PortletURL actionURL = renderResponse.createActionURL();
366: if (req.isRequestedSessionIdValid()) {
367: portletRequestURL = new PortletRequestURL(actionURL
368: .toString(), response.encodeURL(actionURL
369: .toString()));
370: log
371: .debug("WingS-Portlet-Bridge: created PortletRequestURL "
372: + actionURL.toString());
373: // this will fire an event, if the encoding has changed ..
374: session.setProperty("request.url", portletRequestURL);
375: session.setProperty(
376: Const.WINGS_SESSION_PROPERTY_RENDER_RESPONSE,
377: renderResponse);
378:
379: // get the RenderRequest
380: RenderRequest renderRequest = (RenderRequest) req
381: .getAttribute(Const.REQUEST_ATTR_RENDER_REQUEST);
382: if (renderRequest == null) {
383: log
384: .error("WingS-Portlet-Bridge: cant get the request attribute "
385: + Const.REQUEST_ATTR_RENDER_REQUEST);
386: }
387: session.setProperty(
388: Const.WINGS_SESSION_PROPERTY_RENDER_REQUEST,
389: renderRequest);
390: }
391:
392: if (log.isDebugEnabled()) {
393: log.debug("Request URL: " + portletRequestURL);
394: log.debug("HTTP header:");
395: for (Enumeration en = req.getHeaderNames(); en
396: .hasMoreElements();) {
397: String header = (String) en.nextElement();
398: log.debug(" " + header + ": "
399: + req.getHeader(header));
400: }
401: }
402: handleLocale(req);
403:
404: // WingS-Portlet-Bridge: get the Parameter from the map in the request
405: // set by the portlet
406: Map params = (Map) req
407: .getAttribute(Const.REQUEST_ATTR_PARAMETERS_FROM_ACTION_MAP);
408:
409: // The externalizer is able to handle static and dynamic resources
410: ExternalizeManager extManager = getSession()
411: .getExternalizeManager();
412: //WingS-Portlet-Bridge:
413: //String pathInfo = req.getPathInfo(); // Note: Websphere returns <code>null</code> here!
414: String pathInfo = null;
415: if (params != null) {
416: String[] path = (String[]) params
417: .get(Const.REQUEST_PARAM_RESOURCE_AS_PARAM);
418: if (path != null)
419: pathInfo = path[0];
420: }
421:
422: if (pathInfo != null && pathInfo.length() > 0) {
423: // strip of leading /
424: // WingS-Portlet-Bridge:
425: // pathInfo = pathInfo.substring(1);
426: }
427:
428: log.info("WingS-Portlet-Bridge: pathInfo: " + pathInfo);
429:
430: // If we have no path info, or the special '_' path info (that should be explained
431: // somewhere, Holger), then we deliver the top-level frame of this application.
432: String externalizeIdentifier = null;
433: if (pathInfo == null || pathInfo.length() == 0
434: || "_".equals(pathInfo) || firstRequest) {
435: externalizeIdentifier = retrieveCurrentRootFrameResource()
436: .getId();
437: firstRequest = false;
438: } else {
439: externalizeIdentifier = pathInfo;
440: }
441:
442: // Retrieve externalized resource
443: ExternalizedResource extInfo = extManager
444: .getExternalizedResource(externalizeIdentifier);
445:
446: // Special case handling: We request a .html resource of a session which is not accessible.
447: // This happens some times and leads to a 404, though it should not be possible.
448: if (extInfo == null && pathInfo != null
449: && pathInfo.endsWith(".html")) {
450: log
451: .info("Found a request to an invalid .html during a valid session. Redirecting to root frame.");
452: response
453: .sendRedirect(retrieveCurrentRootFrameResource()
454: .getURL().toString());
455: return;
456: }
457:
458: if (extInfo != null
459: && extInfo.getObject() instanceof UpdateResource) {
460: reloadManager.setUpdateMode(true);
461: } else {
462: reloadManager.setUpdateMode(false);
463: }
464:
465: // Prior to dispatching the actual events we have to detect
466: // their epoch and inform the dispatcher which will then be
467: // able to check if the request is valid and processed. If
468: // this is not the case, we force a complete page reload.
469: String ee = "";
470: if (params != null) {
471: String[] eeArray = (String[]) params.get("event_epoch");
472: if (eeArray != null)
473: ee = eeArray[0];
474: }
475: session.getDispatcher().setEventEpoch(ee);
476:
477: // WingS-Portlet-Bridge: Map for the parameters
478: // set by a SPortletAnchor or set in the Portlet
479: Map portletParameters = new HashMap();
480:
481: // Enumeration en = req.getParameterNames();
482: if (params != null) {
483: Set paramNames = params.keySet();
484: Iterator paramNamesIter = paramNames.iterator();
485:
486: Cookie[] cookies = req.getCookies();
487:
488: // are there parameters/low level events to dispatch
489: if (paramNamesIter.hasNext()) {
490: // only fire DISPATCH_START if we have parameters to dispatch
491: session
492: .fireRequestEvent(SRequestEvent.DISPATCH_START);
493:
494: if (cookies != null) {
495: //dispatch cookies
496: for (int i = 0; i < cookies.length; i++) {
497: Cookie cookie = cookies[i];
498: String paramName = cookie.getName();
499: String value = cookie.getValue();
500:
501: if (log.isDebugEnabled())
502: log.debug("dispatching cookie "
503: + paramName + " = " + value);
504:
505: session.getDispatcher().dispatch(paramName,
506: new String[] { value });
507: }
508: }
509:
510: if (log.isDebugEnabled()) {
511: log.debug("Parameters:");
512: for (Enumeration e = req.getParameterNames(); e
513: .hasMoreElements();) {
514: String paramName = (String) e.nextElement();
515: SStringBuilder param = new SStringBuilder();
516: param.append(" ").append(paramName)
517: .append(": ");
518: final String[] values = req
519: .getParameterValues(paramName);
520: param.append(values != null ? Arrays
521: .toString(values) : "null");
522: log.debug(param);
523: }
524: }
525:
526: while (paramNamesIter.hasNext()) {
527: String paramName = (String) paramNamesIter
528: .next();
529: String[] values = (String[]) params
530: .get(paramName);
531:
532: // We do not need to dispatch the event epoch and the XHR request ID
533: if (paramName.equals("event_epoch")
534: || paramName.equals("_xhrID")) {
535: continue;
536: }
537:
538: String value = values[0];
539:
540: // Split the values of the event trigger
541: if (paramName.equals("event_trigger")) {
542: int pos = value.indexOf('|');
543: paramName = value.substring(0, pos);
544: values = new String[] { value
545: .substring(pos + 1) };
546: }
547:
548: // Handle form submit via default button
549: if (paramName.equals("default_button")) {
550: if (value.equals("undefined")) {
551: continue;
552: } else {
553: paramName = values[0];
554: values = new String[] { "1" };
555: }
556: }
557:
558: // WingS-Portlet-Bridge: get the portlet parameters
559: if (paramName
560: .startsWith(Const.WINGS_PORTLET_URL_CODE_STRING)) {
561: log
562: .info("WingS-Portlet-Bridge: getting portlet parameter "
563: + paramName
564: + " = "
565: + Arrays.asList(values));
566: portletParameters.put(PortletParameterCodec
567: .decode(paramName), values);
568: } else {
569: if (log.isDebugEnabled())
570: log
571: .debug("dispatching "
572: + paramName + " = "
573: + Arrays.asList(values));
574: session.getDispatcher().dispatch(paramName,
575: values);
576: }
577:
578: }
579:
580: SForm.fireEvents();
581:
582: // only fire DISPATCH DONE if we have parameters to dispatch
583: session
584: .fireRequestEvent(SRequestEvent.DISPATCH_DONE);
585: }
586: }
587:
588: //WingS-Portlet-Bridge: store the portlet parameters in the session
589: session.setProperty(
590: Const.WINGS_SESSION_PROPERTY_PORTLET_PARAMETER_MAP,
591: portletParameters);
592:
593: session.fireRequestEvent(SRequestEvent.PROCESS_REQUEST);
594: session.getDispatcher().invokeRunnables();
595:
596: // WingS-Portlet-Bridge: fires events if the window state has changed
597: session.fireWindowStateEvents();
598: // WingS-Portlet-Bridge: fires events for the new portlet parameters
599: session.fireNewPortletParameters();
600:
601: // if the user chose to exit the session as a reaction on an
602: // event, we got an URL to redirect after the session.
603: /*
604: * where is the right place?
605: * The right place is
606: * - _after_ we processed the events
607: * (e.g. the 'Pressed Exit-Button'-event or gave
608: * the user the chance to exit this session in the custom
609: * processRequest())
610: * - but _before_ the rendering of the page,
611: * because otherwise an redirect won't work, since we must
612: * not have sent anything to the output stream).
613: */
614: if (session.getExitAddress() != null) {
615:
616: try {
617: session.firePrepareExit();
618: session.fireRequestEvent(SRequestEvent.REQUEST_END);
619:
620: String redirectAddress;
621: if (session.getExitAddress().length() > 0) {
622: // redirect to user requested URL.
623: redirectAddress = session.getExitAddress();
624: } else {
625: // redirect to a fresh session.
626: redirectAddress = req.getRequestURL()
627: .toString();
628: }
629: req.getSession().invalidate(); // calls destroy implicitly
630: response.sendRedirect(redirectAddress);
631: exitSessionWorkaround = redirectAddress;
632: return;
633: } catch (ExitVetoException ex) {
634: session.exit(null);
635: } // end of try-catch
636: }
637:
638: if (session.getRedirectAddress() != null) {
639: handleRedirect(response);
640: return;
641: }
642:
643: reloadManager.notifyCGs();
644: reloadManager.invalidateFrames();
645:
646: // TODO ResourceMapper
647: ResourceMapper mapper = session.getResourceMapper();
648: if (extInfo == null && mapper != null) {
649: //wings-Portlet-Bridge:
650: // Resource res = mapper.mapResource(req.getPathInfo());
651: Resource res = mapper.mapResource(pathInfo);
652: if (res != null) {
653: extInfo = extManager.getExternalizedResource(res
654: .getId());
655: }
656: }
657:
658: if (extInfo != null) {
659: outputDevice = DeviceFactory.createDevice(extInfo);
660: session.fireRequestEvent(SRequestEvent.DELIVER_START,
661: extInfo);
662:
663: long startTime = System.currentTimeMillis();
664: extManager.deliver(extInfo, response, outputDevice);
665: long endTime = System.currentTimeMillis();
666: log
667: .debug("------------------------- Time needed for rendering: "
668: + (endTime - startTime)
669: + " ms -------------------------\n");
670:
671: session.fireRequestEvent(SRequestEvent.DELIVER_DONE,
672: extInfo);
673: } else {
674: handleUnknownResourceRequested(req, response);
675: }
676:
677: } catch (Throwable e) {
678: log.error("Uncaught Exception", e);
679: handleException(response, e);
680: } finally {
681: if (session != null) {
682: session.fireRequestEvent(SRequestEvent.REQUEST_END);
683: }
684:
685: if (outputDevice != null) {
686: try {
687: outputDevice.close();
688: } catch (Exception e) {
689: }
690: }
691:
692: /*
693: * the session might be null due to destroy().
694: */
695: if (session != null) {
696: reloadManager.clear();
697: session.setServletRequest(null);
698: session.setServletResponse(null);
699: }
700:
701: // make sure that the session association to the thread is removed
702: // from the SessionManager
703: SessionManager.removeSession();
704: SForm.clearArmedComponents();
705: }
706: }
707:
708: /**
709: * Searches the current session for the root HTML frame and returns the Resource
710: * representing this root HTML frame (i.e. for you to retrieve the externalizer id
711: * via <code>getId()</code>-method).
712: * @return Resource of the root HTML frame
713: */
714: private Resource retrieveCurrentRootFrameResource()
715: throws ServletException {
716: log.debug("delivering default frame");
717:
718: if (session.getFrames().size() == 0)
719: throw new ServletException("no frame visible");
720:
721: // get the first frame from the set and walk up the hierarchy.
722: // this should work in most cases. if there are more than one
723: // toplevel frames, the developer has to care about the resource
724: // ids anyway ..
725: SFrame defaultFrame = (SFrame) session.getFrames().iterator()
726: .next();
727: while (defaultFrame.getParent() != null)
728: defaultFrame = (SFrame) defaultFrame.getParent();
729:
730: return defaultFrame.getDynamicResource(ReloadResource.class);
731: }
732:
733: private void handleRedirect(HttpServletResponse response)
734: throws IOException {
735: try {
736: ReloadManager reloadManager = session.getReloadManager();
737: if (reloadManager.isUpdateMode()) {
738: String script = "wingS.request.sendRedirect(\""
739: + session.getRedirectAddress() + "\");";
740: session.getScriptManager().addScriptListener(
741: new JavaScriptListener(null, null, script));
742: /*
743: Resource root = retrieveCurrentRootFrameResource();
744: ExternalizedResource externalizedResource = session.getExternalizeManager().getExternalizedResource(root.getId());
745: session.fireRequestEvent(SRequestEvent.DELIVER_START, externalizedResource);
746:
747: String encoding = session.getCharacterEncoding();
748: response.setContentType("text/xml; charset=" + encoding);
749: ServletOutputStream out = response.getOutputStream();
750: Device outputDevice = new ServletDevice(out);
751: UpdateResource.writeHeader(outputDevice);
752: UpdateResource.writeUpdate(outputDevice, "wingS.request.sendRedirect(\"" + session.getRedirectAddress() + "\");");
753: UpdateResource.writeFooter(outputDevice);
754: out.flush();
755:
756: session.fireRequestEvent(SRequestEvent.DELIVER_DONE, externalizedResource);
757: session.fireRequestEvent(SRequestEvent.REQUEST_END);
758:
759: reloadManager.clear();
760: session.setServletRequest(null);
761: session.setServletResponse(null);
762: SessionManager.removeSession();
763: SForm.clearArmedComponents();
764: */
765: } else {
766: response.sendRedirect(session.getRedirectAddress());
767: }
768: } catch (Exception e) {
769: log.warn(e.getMessage(), e);
770: } finally {
771: session.setRedirectAddress(null);
772: }
773: }
774:
775: /**
776: * In case of an error, display an error page to the user. This is only
777: * done if there is a properties <code>wings.error.handler</code> defined
778: * in the web.xml file. If the property is present, the following steps
779: * are performed:
780: * <li> Load the class named by the value of that property, using the
781: * current thread's context class loader,
782: * <li> Instantiate that class using its zero-argument constructor,
783: * <li> Cast the instance to ExceptionHandler,
784: * <li> Invoke the handler's <tt>handle</tt> method, passing it the
785: * <tt>thrown</tt> argument that was passed to this method.
786: * </ol>
787: *
788: * @see DefaultExceptionHandler
789: * @param response the HTTP Response to use
790: * @param thrown the Exception to report
791: */
792: protected void handleException(HttpServletResponse response,
793: Throwable thrown) {
794: try {
795: String className = (String) session
796: .getProperty("wings.error.handler");
797: if (className == null)
798: className = DefaultExceptionHandler.class.getName();
799:
800: ClassLoader classLoader = Thread.currentThread()
801: .getContextClassLoader();
802: Class clazz = classLoader.loadClass(className);
803: ExceptionHandler exceptionHandler = (ExceptionHandler) clazz
804: .newInstance();
805:
806: StringBuilderDevice device = new StringBuilderDevice();
807: exceptionHandler.handle(device, thrown);
808: Resource resource = new StringResource(device.toString(),
809: "html", "text/html");
810: String url = session.getExternalizeManager().externalize(
811: resource);
812:
813: ReloadManager reloadManager = session.getReloadManager();
814: reloadManager.notifyCGs();
815:
816: session.fireRequestEvent(SRequestEvent.DISPATCH_DONE);
817: session.fireRequestEvent(SRequestEvent.PROCESS_REQUEST);
818:
819: if (reloadManager.isUpdateMode()) {
820: Resource root = retrieveCurrentRootFrameResource();
821: ExternalizedResource externalizedResource = session
822: .getExternalizeManager()
823: .getExternalizedResource(root.getId());
824: session.fireRequestEvent(SRequestEvent.DELIVER_START,
825: externalizedResource);
826:
827: String encoding = session.getCharacterEncoding();
828: response
829: .setContentType("text/xml; charset=" + encoding);
830: ServletOutputStream out = response.getOutputStream();
831: Device outputDevice = new ServletDevice(out, encoding);
832: UpdateResource.writeHeader(outputDevice);
833: UpdateResource.writeUpdate(outputDevice,
834: "wingS.request.sendRedirect(\"" + url + "\");");
835: UpdateResource.writeFooter(outputDevice);
836: out.flush();
837:
838: session.fireRequestEvent(SRequestEvent.DELIVER_DONE,
839: externalizedResource);
840: session.fireRequestEvent(SRequestEvent.REQUEST_END);
841:
842: reloadManager.clear();
843: session.setServletRequest(null);
844: session.setServletResponse(null);
845: SessionManager.removeSession();
846: SForm.clearArmedComponents();
847: } else {
848: // TODO FIXME: This redirect is in most times too late. Redirect works only if no byte
849: // has yet been sent to the client (dispatch phase)
850: // Won't work if exception occurred during rendering phase
851: // Solution: Provide / send javascript code to redirect.
852: response.sendRedirect(url);
853: }
854: } catch (Exception e) {
855: log.warn(e.getMessage(), thrown);
856: }
857: }
858:
859: /**
860: * This method is called, whenever a Resource is requested whose
861: * name is not known within this session.
862: *
863: * @param req the causing HttpServletRequest
864: * @param res the HttpServletResponse of this request
865: */
866: protected void handleUnknownResourceRequested(
867: HttpServletRequest req, HttpServletResponse res)
868: throws IOException {
869: res.setStatus(HttpServletResponse.SC_NOT_FOUND);
870: res.setContentType("text/html");
871: res
872: .getOutputStream()
873: .println(
874: "<h1>404 Not Found</h1>Unknown Resource Requested: " /*+ req.getPathInfo()*/);
875: }
876:
877: /* HttpSessionBindingListener */
878: public void valueBound(HttpSessionBindingEvent event) {
879: }
880:
881: /* HttpSessionBindingListener */
882: public void valueUnbound(HttpSessionBindingEvent event) {
883: destroy();
884: }
885:
886: /**
887: * get the Session Encoding, that is appended to each URL.
888: * Basically, this is response.encodeURL(""), but unfortuntatly, this
889: * empty encoding isn't supported by Tomcat 4.x anymore.
890: */
891: public static String getSessionEncoding(HttpServletResponse response) {
892: if (response == null)
893: return "";
894: // encode dummy non-empty URL.
895: return response.encodeURL("foo").substring(3);
896: }
897:
898: /**
899: * Destroy and cleanup the session servlet.
900: */
901: public void destroy() {
902: log.info("destroy called");
903: try {
904: if (session != null) {
905: // Session is needed on destroying the session
906: SessionManager.setSession(session);
907: session.destroy();
908: }
909:
910: // hint the gc.
911: parent = null;
912: session = null;
913: } catch (Exception ex) {
914: log.error("destroy", ex);
915: } finally {
916: SessionManager.removeSession();
917: }
918: }
919:
920: /**
921: * A check if this session servlet seems to be alive or is i.e. invalid because it
922: * was deserialized.
923: *
924: * @return <code>true</code>, if this session servlet seems to be valid and alive.
925: */
926: public boolean isValid() {
927: return session != null && parent != null;
928: }
929: }
|