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.DefaultReloadManager;
018: import org.wings.ReloadManager;
019: import org.wings.SComponent;
020: import org.wings.SContainer;
021: import org.wings.SFrame;
022: import org.wings.SToolTipManager;
023: import org.wings.dnd.DragAndDropManager;
024: import org.wings.event.ExitVetoException;
025: import org.wings.event.SExitEvent;
026: import org.wings.event.SExitListener;
027: import org.wings.event.SRequestEvent;
028: import org.wings.event.SRequestListener;
029: import org.wings.externalizer.ExternalizeManager;
030: import org.wings.externalizer.ExternalizedResource;
031: import org.wings.plaf.CGManager;
032: import org.wings.plaf.LookAndFeel;
033: import org.wings.plaf.LookAndFeelFactory;
034: import org.wings.util.LocaleCharSet;
035: import org.wings.util.StringUtil;
036: import org.wings.util.WeakPropertyChangeSupport;
037:
038: import javax.servlet.ServletConfig;
039: import javax.servlet.ServletContext;
040: import javax.servlet.ServletException;
041: import javax.servlet.http.HttpServletRequest;
042: import javax.servlet.http.HttpServletResponse;
043: import javax.swing.event.EventListenerList;
044: import java.beans.PropertyChangeListener;
045: import java.io.Serializable;
046: import java.util.Collections;
047: import java.util.Enumeration;
048: import java.util.EventListener;
049: import java.util.HashMap;
050: import java.util.HashSet;
051: import java.util.Iterator;
052: import java.util.Locale;
053: import java.util.Map;
054: import java.util.Set;
055:
056: /**
057: * This class represents a wingS session meaning an application user session instance.
058: * Please do not mix this with a servlet {@link javax.servlet.http.HttpSession}!
059: * <p/>A wings Session is a session instance hold by the global {@link WingServlet} servlet. It aggregates all per--user-session
060: * data (mainly the root {@link SFrame}s and provides some information about the client like the browser {@link #getUserAgent()},
061: * the current character encoding {@link #getCharacterEncoding()} or the used Locale {@link #getLocale()}.
062: *
063: * @author <a href="mailto:engels@mercatis.de">Holger Engels</a>
064: */
065: public class Session implements PropertyService, Serializable {
066:
067: private final static Log log = LogFactory.getLog(Session.class);
068:
069: /**
070: * The property name of the locale
071: */
072: public final static String LOCALE_PROPERTY = "locale";
073:
074: /**
075: * The property name of the sessions character encoding
076: */
077: public final static String CHARACTER_ENCODING_PROPERTY = "characterEncoding";
078:
079: /**
080: * The property name of the look&feel
081: */
082: public final static String LOOK_AND_FEEL_PROPERTY = "lookAndFeel";
083:
084: private final SessionStatistics statistics = new SessionStatistics();
085:
086: /**
087: * Every session has its own {@link CGManager}.
088: *
089: */
090: private CGManager CGManager = new CGManager();
091:
092: private SToolTipManager toolTipManager = new SToolTipManager();
093:
094: private ReloadManager reloadManager = null;
095:
096: private MenuManager menuManager = null;
097:
098: private transient ExternalizeManager externalizeManager;
099:
100: private LowLevelEventDispatcher dispatcher = new LowLevelEventDispatcher();
101:
102: private final HashMap<String, Object> props = new HashMap<String, Object>();
103:
104: private final HashSet<SFrame> frames = new HashSet<SFrame>();
105:
106: private long uniqueIdCounter = 1;
107:
108: /**
109: * Maximum upload content length. This is used by the {@link org.wings.session.SessionServlet}
110: * to avoid denial of service attacks.
111: */
112: private int maxContentLength = 64;
113:
114: private transient ServletContext servletContext;
115:
116: private Browser browser;
117:
118: protected transient HttpServletResponse servletResponse;
119:
120: protected transient HttpServletRequest servletRequest;
121:
122: private String redirectAddress;
123:
124: private String exitAddress;
125:
126: private Locale locale = Locale.getDefault();
127:
128: private boolean localeFromHeader = true;
129:
130: private DragAndDropManager dndManager;
131:
132: private ScriptManager scriptManager;
133:
134: /**
135: * Which locales are supported by this servlet. If null, every locale from
136: * the userAgent is accepted. If not null only locales listed in this array
137: * are supported.
138: */
139: private Locale[] supportedLocales = null;
140:
141: /**
142: * The current character encoding used for the communication with the clients userAgent.
143: * If <code>null</code> then the current characterEncoding is determined by the current
144: * session Locale via the charset.properties map.
145: */
146: private String characterEncoding = null;
147:
148: /**
149: * Store here only weak references.
150: */
151: protected final EventListenerList listenerList = new EventListenerList();
152:
153: private final WeakPropertyChangeSupport propertyChangeSupport = new WeakPropertyChangeSupport(
154: this );
155: private ResourceMapper resourceMapper;
156:
157: public final SessionStatistics getStatistics() {
158: return statistics;
159: }
160:
161: static boolean collectStatistics = true;
162:
163: static final SRequestListener SESSION_STATISTIC_COLLECTOR = new SRequestListener() {
164: public void processRequest(SRequestEvent e) {
165: Session session = SessionManager.getSession();
166: if (session == null) {
167: /* while exiting or destroy() the session: it
168: * might already be null in the session manager.
169: */
170: return;
171: }
172: switch (e.getType()) {
173: case SRequestEvent.DISPATCH_START:
174: session.getStatistics().startDispatching();
175: break;
176: case SRequestEvent.DISPATCH_DONE:
177: session.getStatistics().endDispatching();
178: break;
179: case SRequestEvent.DELIVER_START:
180: session.getStatistics().startDelivering();
181: break;
182: case SRequestEvent.DELIVER_DONE:
183: session.getStatistics().endDelivering();
184: break;
185: case SRequestEvent.REQUEST_START:
186: session.getStatistics().startRequest();
187: break;
188: case SRequestEvent.REQUEST_END:
189: session.getStatistics().endRequest();
190: break;
191: }
192: }
193: };
194:
195: public Session() {
196: //log.debug("new session()");
197: if (collectStatistics) {
198: WingsStatistics.getStatistics().incrementSessionCount();
199: WingsStatistics.getStatistics()
200: .incrementActiveSessionCount();
201: WingsStatistics.getStatistics()
202: .incrementAllocatedSessionCount();
203:
204: addRequestListener(SESSION_STATISTIC_COLLECTOR);
205: } // end of if ()
206: }
207:
208: /**
209: * Detect user agent (userAgent). Copy init parameters. Set max content length for uploads / requests.
210: * Install look and feel.
211: *
212: * @param servletConfig a <code>ServletConfig</code> value
213: * @param request a <code>HttpServletRequest</code> value
214: * @param response
215: * @throws ServletException if an error occurs
216: */
217: public void init(ServletConfig servletConfig,
218: HttpServletRequest request, HttpServletResponse response)
219: throws ServletException {
220: servletContext = request.getSession().getServletContext();
221: setServletRequest(request);
222: setServletResponse(response);
223: setUserAgentFromRequest(request);
224:
225: initProps(servletConfig);
226: initMaxContentLength();
227:
228: try {
229: LookAndFeel lookAndFeel = LookAndFeelFactory
230: .getLookAndFeelFactory().create();
231: CGManager.setLookAndFeel(lookAndFeel);
232: } catch (Exception ex) {
233: log
234: .fatal(
235: "could not load look and feel: "
236: + servletContext
237: .getInitParameter("wings.lookandfeel.factory"),
238: ex);
239: throw new ServletException(ex);
240: }
241: }
242:
243: /**
244: * Detect user agent (userAgent). Copy init parameters. Set max content length for uploads / requests.
245: * Install look and feel.
246: *
247: * @param request a <code>HttpServletRequest</code> value
248: * @throws ServletException if an error occurs
249: */
250: public void init(HttpServletRequest request)
251: throws ServletException {
252: servletContext = request.getSession().getServletContext();
253: setServletRequest(request);
254: setUserAgentFromRequest(request);
255:
256: initProps(request.getSession().getServletContext());
257: initMaxContentLength();
258:
259: try {
260: LookAndFeel lookAndFeel = LookAndFeelFactory
261: .getLookAndFeelFactory().create();
262: CGManager.setLookAndFeel(lookAndFeel);
263: } catch (Exception ex) {
264: log
265: .fatal(
266: "could not load look and feel: "
267: + servletContext
268: .getInitParameter("wings.lookandfeel.factory"),
269: ex);
270: throw new ServletException(ex);
271: }
272: }
273:
274: protected void initMaxContentLength() {
275: String maxCL = getServletContext().getInitParameter(
276: "content.maxlength");
277: if (maxCL != null) {
278: try {
279: maxContentLength = Integer.parseInt(maxCL);
280: } catch (NumberFormatException e) {
281: log.warn("invalid content.maxlength: " + maxCL, e);
282: }
283: }
284: }
285:
286: /**
287: * Copy the init parameters.
288: */
289: protected void initProps(ServletConfig servletConfig) {
290: Enumeration params = servletConfig.getInitParameterNames();
291: while (params.hasMoreElements()) {
292: String name = (String) params.nextElement();
293: props.put(name, servletConfig.getInitParameter(name));
294: }
295: }
296:
297: protected void initProps(ServletContext servletContext) {
298: Enumeration params = servletContext.getInitParameterNames();
299: while (params.hasMoreElements()) {
300: String name = (String) params.nextElement();
301: props.put(name, servletContext.getInitParameter(name));
302: }
303: }
304:
305: void setServletRequest(HttpServletRequest servletRequest) {
306: this .servletRequest = servletRequest;
307: }
308:
309: public HttpServletRequest getServletRequest() {
310: return servletRequest;
311: }
312:
313: /**
314: * Sets the current servlet response in progress. Used by wingS framework
315: */
316: void setServletResponse(HttpServletResponse servletResponse) {
317: this .servletResponse = servletResponse;
318: }
319:
320: /**
321: * The current HTTP servlet response which the framework will deliver
322: * after processing the current request. This is a part of the Servlet
323: * architecture.
324: *
325: * @return The current servlet response about to send to the client
326: */
327: public HttpServletResponse getServletResponse() {
328: return servletResponse;
329: }
330:
331: /**
332: * The current servlet context provided by the underlying
333: * servlet container.
334: * This value is retrieved from the initial servlet request
335: * for this session.
336: *
337: * @return The current servlet context provided by the underlying
338: * servlet container.
339: */
340: public ServletContext getServletContext() {
341: return servletContext;
342: }
343:
344: /**
345: * Override the current reload manager.
346: *
347: * @param reloadManager You customized reload manager implementation.
348: */
349: public void setReloadManager(ReloadManager reloadManager) {
350: this .reloadManager = reloadManager;
351: }
352:
353: /**
354: * The reload manager responsible for the component invalidation
355: * of the components contained in this wingS session. (Epoch counter)
356: *
357: * @return Lazily constructs {@link DefaultReloadManager} if no other reload
358: * manager has been set
359: */
360: public ReloadManager getReloadManager() {
361: if (reloadManager == null)
362: reloadManager = new DefaultReloadManager();
363: return reloadManager;
364: }
365:
366: public MenuManager getMenuManager() {
367: if (menuManager == null)
368: menuManager = new MenuManager();
369: return menuManager;
370: }
371:
372: /**
373: * The Externalize manager is response to provide all {@link org.wings.Resource}
374: * via HTTP to the client.
375: *
376: * @return The externalize manager responsible to externalize all sort
377: * of resources contained in this session.
378: */
379: public ExternalizeManager getExternalizeManager() {
380: if (externalizeManager == null)
381: externalizeManager = new ExternalizeManager();
382: return externalizeManager;
383: }
384:
385: /**
386: * The Script manager collects scripts
387: *
388: * @return The script manager responsible to script all sort
389: * of resources contained in this session.
390: */
391: public ScriptManager getScriptManager() {
392: if (scriptManager == null)
393: scriptManager = new ScriptManager();
394: return scriptManager;
395: }
396:
397: /**
398: * The CG manager is responsible to provide the renderer implementation (aka. PLAF)
399: * for a given component class.
400: *
401: * @return The current CG manager
402: */
403: public CGManager getCGManager() {
404: return CGManager;
405: }
406:
407: /**
408: * @return The tooltip manager object containing configuration values on the components
409: * tooltip behaviour
410: */
411: public SToolTipManager getToolTipManager() {
412: return toolTipManager;
413: }
414:
415: /**
416: * Returns the current browser of the client detected by the
417: * <code>User-Agent</code> parameter of the initial HTTP request
418: * for this user session.
419: *
420: * @return A {@link Browser} object providing browser type, os type and
421: * other informations from the HTTP <code>User-Agent</code> string.
422: */
423: public Browser getUserAgent() {
424: return browser;
425: }
426:
427: /* * This would be a better naming!
428: * Returns the current browser of the client detected by the
429: * <code>User-Agent</code> parameter of the initial HTTP request
430: * for this user session.
431: *
432: * @return A {@link Browser} object providing browser type, os type and
433: * other informations from the HTTP <code>User-Agent</code> string.
434: * /
435: public Browser getBrowser() {
436: return browser;
437: } */
438:
439: /**
440: * Describe <code>setUserAgentFromRequest</code> method here.
441: *
442: * @param request a <code>HttpServletRequest</code> value
443: */
444: public void setUserAgentFromRequest(HttpServletRequest request) {
445: try {
446: final String userAgentString = request
447: .getHeader("User-Agent");
448: browser = new Browser(userAgentString);
449: log.debug("Browser is detected as " + browser
450: + ". User-Agent was: " + userAgentString);
451: log.debug("major version = " + browser.getMajorVersion()
452: + ", id = " + browser.getBrowserType().getId());
453: log.debug("short name = "
454: + browser.getBrowserType().getShortName());
455: } catch (Exception ex) {
456: log.warn("Cannot get User-Agent from request", ex);
457: }
458: }
459:
460: /**
461: * The low level event dispatcher is responsible for taking an HTTP request,
462: * parse it contents and delegate the so called low level events to the
463: * registered {@link org.wings.LowLevelEventListener}s (i.e. Buttons, etc.)
464: *
465: * @return The low level event dispatcher responsible for this session.
466: */
467: public LowLevelEventDispatcher getDispatcher() {
468: return dispatcher;
469: }
470:
471: /**
472: * Describe <code>addFrame</code> method here.
473: *
474: * @param frame a <code>SFrame</code> value
475: */
476: public void addFrame(SFrame frame) {
477: frames.add(frame);
478: }
479:
480: /**
481: * Describe <code>removeFrame</code> method here.
482: *
483: * @param frame a <code>SFrame</code> value
484: */
485: public void removeFrame(SFrame frame) {
486: frames.remove(frame);
487: }
488:
489: /**
490: * Describe <code>frames</code> method here.
491: *
492: * @return a <code>Set</code> value
493: */
494: public Set<SFrame> getFrames() {
495: return Collections.unmodifiableSet(frames);
496: }
497:
498: /**
499: * The root frame is the first shown frame.
500: *
501: * @return a <code>SFrame</code> value
502: */
503: public SFrame getRootFrame() {
504: if (frames.isEmpty())
505: return null;
506:
507: SFrame rootFrame = frames.iterator().next();
508: while (rootFrame.getParent() != null)
509: rootFrame = (SFrame) rootFrame.getParent();
510:
511: return rootFrame;
512: }
513:
514: public SComponent getComponentByName(String name) {
515: return getComponentByName(this .getRootFrame(), name);
516: }
517:
518: /**
519: * Search in the given SContainer for the SComponent with the given name.
520: * @param container The SContainer where you want to search for the SComponent with the given name.
521: * @param name The Name of the SComponent
522: * @return the SComponent with the given name
523: */
524: public SComponent getComponentByName(SContainer container,
525: String name) {
526: SComponent component = null;
527: SComponent[] components = container.getComponents();
528: for (int x = 0, y = components.length; x < y; x++) {
529: SComponent component_x = components[x];
530: if (component_x.getName().equals(name)) {
531: component = component_x;
532: break;
533: } else if (component_x instanceof SContainer) {
534: component = getComponentByName(
535: (SContainer) component_x, name);
536: if (component != null) {
537: break;
538: }
539: }
540: }
541: return component;
542: }
543:
544: /**
545: * Describe <code>getProperties</code> method here.
546: *
547: * @return a <code>Map</code> value
548: */
549: public final Map getProperties() {
550: return Collections.unmodifiableMap(props);
551: }
552:
553: /**
554: * Gets the session property indicated by the specified key.
555: *
556: * @param key the name of the session property.
557: * @return the string value of the session property,
558: * or <code>null</code> if there is no property with that key.
559: */
560: public Object getProperty(String key) {
561: return props.get(key);
562: }
563:
564: /**
565: * Gets the session property indicated by the specified key.
566: *
567: * @param key the name of the session property.
568: * @param def a default value.
569: * @return the string value of the session property,
570: * or the default value if there is no property with that key.
571: * @see org.wings.session.PropertyService#getProperties()
572: */
573: public Object getProperty(String key, Object def) {
574: if (!props.containsKey(key)) {
575: return def;
576: } else {
577: return props.get(key);
578: }
579: }
580:
581: /**
582: * Sets the session property indicated by the specified key.
583: *
584: * @param key the name of the session property.
585: * @param value the value of the session property.
586: * @return the previous value of the session property,
587: * or <code>null</code> if it did not have one.
588: * @see org.wings.session.PropertyService#getProperty(java.lang.String)
589: * @see org.wings.session.PropertyService#getProperty(java.lang.String, java.lang.Object)
590: */
591: public Object setProperty(String key, Object value) {
592: Object old = props.put(key, value);
593: propertyChangeSupport.firePropertyChange(key, old, value);
594: return old;
595: }
596:
597: /* @see PropertyService */
598: public boolean containsProperty(String key) {
599: return props.containsKey(key);
600: }
601:
602: /* @see PropertyService */
603: public Object removeProperty(String key) {
604: Object old = props.remove(key);
605: propertyChangeSupport.firePropertyChange(key, old, null);
606: return old;
607: }
608:
609: public void addPropertyChangeListener(
610: PropertyChangeListener listener) {
611: propertyChangeSupport.addPropertyChangeListener(listener);
612: }
613:
614: public void removePropertyChangeListener(
615: PropertyChangeListener listener) {
616: propertyChangeSupport.removePropertyChangeListener(listener);
617: }
618:
619: /**
620: * Describe <code>addPropertyChangeListener</code> method here.
621: *
622: * @param propertyName a <code>String</code> value
623: * @param listener a <code>PropertyChangeListener</code> value
624: */
625: public void addPropertyChangeListener(String propertyName,
626: PropertyChangeListener listener) {
627: propertyChangeSupport.addPropertyChangeListener(propertyName,
628: listener);
629: }
630:
631: /**
632: * Describe <code>removePropertyChangeListener</code> method here.
633: *
634: * @param propertyName a <code>String</code> value
635: * @param listener a <code>PropertyChangeListener</code> value
636: */
637: public void removePropertyChangeListener(String propertyName,
638: PropertyChangeListener listener) {
639: propertyChangeSupport.addPropertyChangeListener(propertyName,
640: listener);
641: }
642:
643: /**
644: * Sets the locale for this session. A property change event is fired, if the locale has actually changed.
645: *
646: * @param locale the locale to be associated with this session.
647: */
648: public void setLocale(Locale locale)
649: throws IllegalArgumentException {
650: Locale old = this .locale;
651: if (locale == null || this .locale.equals(locale))
652: return;
653:
654: this .locale = locale;
655: propertyChangeSupport.firePropertyChange(LOCALE_PROPERTY, old,
656: locale);
657: }
658:
659: /**
660: * The Locale of the current session. This Locale reflects the Locale of the clients userAgent.
661: *
662: * @return a <code>Locale</code> value
663: */
664: public Locale getLocale() {
665: return locale;
666: }
667:
668: /**
669: * Indicates if the wings session servlet should adopt the clients Locale provided by the
670: * browsers in the HTTP header.
671: *
672: * @param adoptLocale if true, try to determine, false ignore
673: */
674: public final void setLocaleFromHeader(boolean adoptLocale) {
675: localeFromHeader = adoptLocale;
676: if (localeFromHeader)
677: determineLocale();
678: }
679:
680: /**
681: * Indicates if the wings session servlet should adopt the clients Locale provided by the
682: * browsers in the HTTP header.
683: */
684: public final boolean getLocaleFromHeader() {
685: return localeFromHeader;
686: }
687:
688: /**
689: * sets the locales, supported by this application. If empty or <em>null</em>, all locales are supported.
690: */
691: public final void setSupportedLocales(Locale[] locales) {
692: supportedLocales = locales;
693: localeFromHeader = true;
694: determineLocale();
695: }
696:
697: void determineLocale() {
698: if (supportedLocales == null)
699: setLocale(servletRequest.getLocale());
700:
701: Enumeration<Locale> requestedLocales = servletRequest
702: .getLocales();
703: if (supportedLocales != null) {
704: while (requestedLocales.hasMoreElements()) {
705: Locale locale = requestedLocales.nextElement();
706: for (int i = 0; i < supportedLocales.length; i++) {
707: Locale supportedLocale = supportedLocales[i];
708: if (locale.equals(supportedLocale)) {
709: setLocale(supportedLocale);
710: return;
711: }
712: }
713: }
714: log.warn("locale not supported " + locale);
715: setLocale(supportedLocales[0]);
716: } else
717: setLocale(requestedLocales.nextElement());
718: }
719:
720: /**
721: * Returns the locales, supported by this application. If empty or <em>null</em>, all locales are supported.
722: */
723: public final Locale[] getSupportedLocales() {
724: return supportedLocales;
725: }
726:
727: /**
728: * The current character encoding used for the communication with the clients userAgent.
729: * If <code>null</code> then the current characterEncoding is determined by the current
730: * session Locale via the charset.properties map.
731: *
732: * @param characterEncoding The charcterEncoding which should be enforces for this session (i.e. "utf-8"),
733: * or <code>null</code> if it should be determined by the clients userAgent Locale.
734: */
735: public void setCharacterEncoding(String characterEncoding) {
736: String oldEncoding = this .characterEncoding;
737: this .characterEncoding = characterEncoding;
738: propertyChangeSupport.firePropertyChange(
739: CHARACTER_ENCODING_PROPERTY, oldEncoding,
740: characterEncoding);
741: }
742:
743: /**
744: * The current character encoding used for the communication with the clients userAgent.
745: * If <code>null</code> then the current characterEncoding is determined by the current
746: * session Locale via the charset.properties map.
747: *
748: * @return The characterEncoding set for this sesson or determined by the current Locale.
749: */
750: public String getCharacterEncoding() {
751: if (this .characterEncoding == null) {
752: return LocaleCharSet.getInstance().getCharSet(getLocale());
753: } else {
754: return this .characterEncoding;
755: }
756: }
757:
758: private final long getUniqueId() {
759: return uniqueIdCounter++;
760: }
761:
762: /**
763: * Creates a session context unique ID, that can be used as an identifier,
764: * i.e. it is guaranteed to start with a letter
765: *
766: * @return a <code>String</code> value
767: */
768: public String createUniqueId() {
769: return StringUtil.toIdentifierString(getUniqueId());
770: }
771:
772: /**
773: * Get the maximum content length (file size) for a post
774: * request.
775: *
776: * @return maximum size in kB (1024 Byte)
777: * @see org.wings.session.MultipartRequest
778: */
779: public final int getMaxContentLength() {
780: return maxContentLength;
781: }
782:
783: /**
784: * Set the maximum content length (file size) for a post
785: * request.
786: *
787: * @param l size in kB (1024 Byte)
788: * @see org.wings.session.MultipartRequest
789: */
790: public final void setMaxContentLength(int l) {
791: maxContentLength = l;
792: }
793:
794: protected void destroy() {
795:
796: try {
797: firePrepareExit(true);
798: } catch (ExitVetoException ex) {
799: // ignore this, because no veto possible
800: }
801:
802: if (collectStatistics) {
803: WingsStatistics.getStatistics()
804: .decrementActiveSessionCount();
805: } // end of if ()
806:
807: Iterator it = frames.iterator();
808: while (it.hasNext()) {
809: SContainer container = ((SFrame) it.next())
810: .getContentPane();
811: if (container != null)
812: container.removeAll();
813: }
814:
815: reloadManager.clear();
816: reloadManager = null;
817: if (externalizeManager != null) // eexternalizeManager is transient!
818: externalizeManager.clear();
819: externalizeManager = null;
820: dispatcher.clear();
821: dispatcher = null;
822:
823: frames.clear();
824: props.clear();
825:
826: Object[] listeners = listenerList.getListenerList();
827: for (int i = listeners.length - 2; i >= 0; i -= 2) {
828: listenerList.remove((Class) listeners[i],
829: (EventListener) listeners[i + 1]);
830: } // end of for (int i=0; i<; i++)
831:
832: }
833:
834: /**
835: * Exit the current session and redirect to other URL.
836: * <p/>
837: * This removes the session and its associated
838: * application from memory. The userAgent is redirected to the given
839: * URL. Note, that it is not even possible for the user to re-enter
840: * the application with the BACK-button, since all information is
841: * removed.
842: * <p/>
843: * <em>Always</em> exit an application by calling an
844: * <code>exit()</code> method, especially, if it is an application
845: * that requires a login and thus handles sensitive information accessible
846: * through the session. Usually, you will call this on behalf of an
847: * event within an <code>ActionListener.actionPerformed()</code> like for
848: * a pressed 'EXIT'-Button.
849: *
850: * @param redirectAddress the address, the userAgent is redirected after
851: * removing this session. This must be a String
852: * containing the complete URL (no relative URL)
853: * to the place to be redirected. If 'null', nothing
854: * happens.
855: */
856: public void exit(String redirectAddress) {
857: this .exitAddress = redirectAddress;
858: }
859:
860: /**
861: * Exit the current session and redirect to new application instance.
862: * <p/>
863: * This removes the session and its associated
864: * application from memory. The userAgent is redirected to the same
865: * application with a fresh session. Note, that it is not even
866: * possible for the user to re-enter the old application with the
867: * BACK-button, since all information is removed.
868: * <p/>
869: * <em>Always</em> exit an application by calling an
870: * <code>exit()</code> method, especially, if it is an application
871: * that requires an login and thus handles sensitive information accessible
872: * through the session. Usually, you will call this on behalf of an
873: * event within an <code>ActionListener.actionPerformed()</code> like for
874: * a pressed 'EXIT'-Button.
875: */
876: public void exit() {
877: exit("");
878: }
879:
880: public String getExitAddress() {
881: return exitAddress;
882: }
883:
884: public String getRedirectAddress() {
885: return redirectAddress;
886: }
887:
888: public void setRedirectAddress(String redirectAddress) {
889: this .redirectAddress = redirectAddress;
890: }
891:
892: public void addExitListener(SExitListener listener) {
893: listenerList.add(SExitListener.class, listener);
894: }
895:
896: public void removeExitListener(SExitListener listener) {
897: listenerList.remove(SExitListener.class, listener);
898: }
899:
900: public SExitListener[] getExitListeners() {
901: return (SExitListener[]) listenerList
902: .getListeners(SExitListener.class);
903: }
904:
905: /**
906: * Fire an RequestEvent at each registered listener.
907: */
908: final void firePrepareExit() throws ExitVetoException {
909: firePrepareExit(false);
910: }
911:
912: final void firePrepareExit(boolean ignoreVeto)
913: throws ExitVetoException {
914: SExitEvent event = null;
915:
916: Object[] listeners = listenerList.getListenerList();
917: for (int i = listeners.length - 2; i >= 0; i -= 2) {
918: if (listeners[i] == SExitListener.class) {
919: // Lazily create the event:
920: if (event == null) {
921: event = new SExitEvent(this );
922: }
923: try {
924: ((SExitListener) listeners[i + 1])
925: .prepareExit(event);
926: } catch (ExitVetoException ex) {
927: if (!ignoreVeto) {
928: throw ex;
929: }
930: }
931: }
932: }
933: }
934:
935: public void addRequestListener(SRequestListener listener) {
936: listenerList.add(SRequestListener.class, listener);
937: }
938:
939: public void removeRequestListener(SRequestListener listener) {
940: listenerList.remove(SRequestListener.class, listener);
941: }
942:
943: /**
944: * Fire an RequestEvent at each registered listener.
945: */
946: void fireRequestEvent(int type) {
947: fireRequestEvent(type, null);
948: }
949:
950: /**
951: * Fire an RequestEvent at each registered listener.
952: */
953: void fireRequestEvent(int type, ExternalizedResource resource) {
954: SRequestEvent event = null;
955:
956: Object[] listeners = listenerList.getListenerList();
957: for (int i = listeners.length - 2; i >= 0; i -= 2) {
958: if (listeners[i] == SRequestListener.class) {
959: // Lazily create the event:
960: if (event == null) {
961: event = new SRequestEvent(this , type, resource);
962: }
963: ((SRequestListener) listeners[i + 1])
964: .processRequest(event);
965: }
966: }
967: }
968:
969: protected void finalize() {
970: log.debug("gc session");
971: if (collectStatistics) {
972: WingsStatistics.getStatistics()
973: .decrementAllocatedSessionCount();
974: } // end of if ()
975: }
976:
977: public boolean hasDragAndDropManager() {
978: return dndManager != null;
979: }
980:
981: public DragAndDropManager getDragAndDropManager() {
982: if (dndManager == null) {
983: dndManager = new DragAndDropManager();
984: }
985: return dndManager;
986: }
987:
988: public void setDndManager(DragAndDropManager dndManager) {
989: this .dndManager = dndManager;
990: }
991:
992: public ResourceMapper getResourceMapper() {
993: return resourceMapper;
994: }
995:
996: public void setResourceMapper(ResourceMapper resourceMapper) {
997: this.resourceMapper = resourceMapper;
998: }
999: }
|