KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * $Id: Session.java,v 1.12 2005/05/27 15:11:38 neurolabs 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
17 import java.beans.PropertyChangeListener JavaDoc;
18 import java.io.Serializable JavaDoc;
19 import java.util.Arrays JavaDoc;
20 import java.util.Collections JavaDoc;
21 import java.util.Enumeration JavaDoc;
22 import java.util.EventListener JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.HashSet JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.Locale JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.Set JavaDoc;
29
30 import javax.servlet.ServletConfig JavaDoc;
31 import javax.servlet.ServletContext JavaDoc;
32 import javax.servlet.ServletException JavaDoc;
33 import javax.servlet.http.HttpServletRequest JavaDoc;
34 import javax.servlet.http.HttpServletResponse JavaDoc;
35 import javax.swing.event.EventListenerList JavaDoc;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.wings.DefaultReloadManager;
40 import org.wings.ReloadManager;
41 import org.wings.SContainer;
42 import org.wings.SFrame;
43 import org.wings.SToolTipManager;
44 import org.wings.event.ExitVetoException;
45 import org.wings.event.SExitEvent;
46 import org.wings.event.SExitListener;
47 import org.wings.event.SRequestEvent;
48 import org.wings.event.SRequestListener;
49 import org.wings.externalizer.ExternalizeManager;
50 import org.wings.externalizer.ExternalizedResource;
51 import org.wings.plaf.CGManager;
52 import org.wings.plaf.LookAndFeel;
53 import org.wings.plaf.LookAndFeelFactory;
54 import org.wings.util.LocaleCharSet;
55 import org.wings.util.StringUtil;
56 import org.wings.util.WeakPropertyChangeSupport;
57
58 /**
59  * @author <a HREF="mailto:engels@mercatis.de">Holger Engels</a>
60  * @version $Revision: 1.12 $
61  */

62 public class Session
63         implements PropertyService, Serializable JavaDoc {
64
65     private final transient static Log log = LogFactory.getLog(Session.class);
66
67     /**
68      * The property name of the locale
69      */

70     public final static String JavaDoc LOCALE_PROPERTY = "locale";
71
72     /**
73      * The property name of the look&feel
74      */

75     public final static String JavaDoc LOOK_AND_FEEL_PROPERTY = "lookAndFeel";
76
77     private final SessionStatistics statistics = new SessionStatistics();
78
79     /**
80      * Every session has its own {@link CGManager}.
81      *
82      */

83     private CGManager CGManager = new CGManager();
84
85     private SToolTipManager toolTipManager = new SToolTipManager();
86
87     private ReloadManager reloadManager = null;
88
89     private ExternalizeManager externalizeManager = new ExternalizeManager();
90
91     private LowLevelEventDispatcher dispatcher = new LowLevelEventDispatcher();
92
93     private final HashMap JavaDoc props = new HashMap JavaDoc();
94
95     private final HashSet JavaDoc frames = new HashSet JavaDoc();
96
97     private long uniqueIdCounter = 1;
98
99     /**
100      * Maximum upload content length. This is used by the {@link org.wings.session.SessionServlet}
101      * to avoid denial of service attacks.
102      */

103     private int maxContentLength = 64;
104
105     private transient ServletContext JavaDoc servletContext;
106
107     private transient Browser userAgent;
108
109     protected transient HttpServletResponse JavaDoc servletResponse;
110
111     protected transient HttpServletRequest JavaDoc servletRequest;
112
113     private String JavaDoc redirectAddress;
114
115     private String JavaDoc exitAddress;
116
117     private Locale JavaDoc locale = Locale.getDefault();
118
119     private boolean localeFromHeader = true;
120
121     /**
122      * Which locales are supported by this servlet. If null, every locale from
123      * the userAgent is accepted. If not null only locales listed in this array
124      * are supported.
125      */

126     private Locale JavaDoc[] supportedLocales = null;
127
128     /**
129      * The current character encoding used for the communication with the clients userAgent.
130      * If <code>null</code> then the current characterEncoding is determined by the current
131      * session Locale via the charset.properties map.
132      */

133     private String JavaDoc characterEncoding = null;
134
135
136     /**
137      * Store here only weak references.
138      */

139     protected final EventListenerList JavaDoc listenerList = new EventListenerList JavaDoc();
140
141     public final SessionStatistics getStatistics() {
142         return statistics;
143     }
144
145     static boolean collectStatistics = true;
146
147     static final SRequestListener SESSION_STATISTIC_COLLECTOR = new SRequestListener() {
148         public void processRequest(SRequestEvent e) {
149             Session session = SessionManager.getSession();
150             if (session == null) {
151                 /* while exiting or destroy() the session: it
152                  * might already be null in the session manager.
153                  */

154                 return;
155             }
156             switch (e.getType()) {
157                 case SRequestEvent.DISPATCH_START:
158                     session.getStatistics().startDispatching();
159                     break;
160                 case SRequestEvent.DISPATCH_DONE:
161                     session.getStatistics().endDispatching();
162                     break;
163                 case SRequestEvent.DELIVER_START:
164                     session.getStatistics().startDelivering();
165                     break;
166                 case SRequestEvent.DELIVER_DONE:
167                     session.getStatistics().endDelivering();
168                     break;
169                 case SRequestEvent.REQUEST_START:
170                     session.getStatistics().startRequest();
171                     break;
172                 case SRequestEvent.REQUEST_END:
173                     session.getStatistics().endRequest();
174                     break;
175             }
176         }
177     };
178
179
180     public Session() {
181         if (collectStatistics) {
182             WingsStatistics.getStatistics().incrementSessionCount();
183             WingsStatistics.getStatistics().incrementActiveSessionCount();
184             WingsStatistics.getStatistics().incrementAllocatedSessionCount();
185
186             addRequestListener(SESSION_STATISTIC_COLLECTOR);
187         } // end of if ()
188
}
189
190     /**
191      * Detect user agent (userAgent). Copy init parameters. Set max content length for uploads / requests.
192      * Install look and feel.
193      *
194      * @param servletConfig a <code>ServletConfig</code> value
195      * @param request a <code>HttpServletRequest</code> value
196      * @throws ServletException if an error occurs
197      */

198     public void init(ServletConfig JavaDoc servletConfig, HttpServletRequest JavaDoc request) throws ServletException JavaDoc {
199         servletContext = request.getSession().getServletContext();
200         setServletRequest(request);
201         setUserAgentFromRequest(request);
202
203         initProps(servletConfig);
204         initMaxContentLength();
205
206         try {
207             LookAndFeel lookAndFeel = LookAndFeelFactory.getLookAndFeelFactory().create();
208             CGManager.setLookAndFeel(lookAndFeel);
209         } catch (Exception JavaDoc ex) {
210             log.fatal("could not load look and feel: " +
211                     servletContext.getInitParameter("wings.lookandfeel.factory"), ex);
212             throw new ServletException JavaDoc(ex);
213         }
214
215     }
216
217     protected void initMaxContentLength() {
218         String JavaDoc maxCL = servletContext.getInitParameter("content.maxlength");
219         if (maxCL != null) {
220             try {
221                 maxContentLength = Integer.parseInt(maxCL);
222             } catch (NumberFormatException JavaDoc e) {
223                 log.warn("invalid content.maxlength: " + maxCL, e);
224             }
225         }
226     }
227
228     /**
229      * Copy the init parameters.
230      */

231     protected void initProps(ServletConfig JavaDoc servletConfig) {
232         Enumeration JavaDoc params = servletConfig.getInitParameterNames();
233         while (params.hasMoreElements()) {
234             String JavaDoc name = (String JavaDoc) params.nextElement();
235             props.put(name, servletConfig.getInitParameter(name));
236         }
237     }
238
239     void setServletRequest(HttpServletRequest JavaDoc servletRequest) {
240         this.servletRequest = servletRequest;
241     }
242
243
244     public HttpServletRequest JavaDoc getServletRequest() {
245         return servletRequest;
246     }
247
248     void setServletResponse(HttpServletResponse JavaDoc servletResponse) {
249         this.servletResponse = servletResponse;
250     }
251
252     public HttpServletResponse JavaDoc getServletResponse() {
253         return servletResponse;
254     }
255
256     public ServletContext JavaDoc getServletContext() {
257         return servletContext;
258     }
259
260     public void setReloadManager(ReloadManager reloadManager) {
261         this.reloadManager = reloadManager;
262     }
263
264     public ReloadManager getReloadManager() {
265         if (reloadManager == null)
266             reloadManager = new DefaultReloadManager();
267         return reloadManager;
268     }
269
270     public ExternalizeManager getExternalizeManager() {
271         return externalizeManager;
272     }
273
274     public CGManager getCGManager() {
275         return CGManager;
276     }
277
278     public SToolTipManager getToolTipManager() {
279         return toolTipManager;
280     }
281
282     /**
283      * Get the user agent (userAgent) used for
284      * this session by the user.
285      *
286      * @return a <code>Browser</code> value
287      */

288     public Browser getUserAgent() {
289         return userAgent;
290     }
291
292     /**
293      * Describe <code>setUserAgentFromRequest</code> method here.
294      *
295      * @param request a <code>HttpServletRequest</code> value
296      */

297     public void setUserAgentFromRequest(HttpServletRequest JavaDoc request) {
298         try {
299             userAgent = new Browser(request.getHeader("User-Agent"));
300             log.debug("User-Agent is " + userAgent);
301         } catch (Exception JavaDoc ex) {
302             log.warn("Cannot get User-Agent from request", ex);
303         }
304     }
305
306
307     public LowLevelEventDispatcher getDispatcher() {
308         return dispatcher;
309     }
310
311     /**
312      * Describe <code>addFrame</code> method here.
313      *
314      * @param frame a <code>SFrame</code> value
315      */

316     public void addFrame(SFrame frame) {
317         frames.add(frame);
318     }
319
320     /**
321      * Describe <code>removeFrame</code> method here.
322      *
323      * @param frame a <code>SFrame</code> value
324      */

325     public void removeFrame(SFrame frame) {
326         frames.remove(frame);
327     }
328
329     /**
330      * Describe <code>frames</code> method here.
331      *
332      * @return a <code>Set</code> value
333      */

334     public Set JavaDoc getFrames() {
335         return frames;
336     }
337
338     /**
339      * The root frame is the first shown frame.
340      *
341      * @return a <code>SFrame</code> value
342      */

343     public SFrame getRootFrame() {
344         if (frames.size() == 0)
345             return null;
346
347         SFrame rootFrame = (SFrame) frames.iterator().next();
348         while (rootFrame.getParent() != null)
349             rootFrame = (SFrame) rootFrame.getParent();
350
351         return rootFrame;
352     }
353
354     /**
355      * Describe <code>getProperties</code> method here.
356      *
357      * @return a <code>Map</code> value
358      */

359     public final Map JavaDoc getProperties() {
360         return Collections.unmodifiableMap(props);
361     }
362
363     /**
364      * Gets the session property indicated by the specified key.
365      *
366      * @param key the name of the session property.
367      * @return the string value of the session property,
368      * or <code>null</code> if there is no property with that key.
369      */

370     public Object JavaDoc getProperty(String JavaDoc key) {
371         return props.get(key);
372     }
373
374     /**
375      * Gets the session property indicated by the specified key.
376      *
377      * @param key the name of the session property.
378      * @param def a default value.
379      * @return the string value of the session property,
380      * or the default value if there is no property with that key.
381      * @see org.wings.session.PropertyService#getProperties()
382      */

383     public Object JavaDoc getProperty(String JavaDoc key, Object JavaDoc def) {
384         if (!props.containsKey(key)) {
385             return def;
386         } else {
387             return props.get(key);
388         }
389     }
390
391     /**
392      * Sets the session property indicated by the specified key.
393      *
394      * @param key the name of the session property.
395      * @param value the value of the session property.
396      * @return the previous value of the session property,
397      * or <code>null</code> if it did not have one.
398      * @see org.wings.session.PropertyService#getProperty(java.lang.String)
399      * @see org.wings.session.PropertyService#getProperty(java.lang.String, java.lang.Object)
400      */

401     public Object JavaDoc setProperty(String JavaDoc key, Object JavaDoc value) {
402         //System.err.print("DefaultSession.setProperty");
403
Object JavaDoc old = props.put(key, value);
404         propertyChangeSupport.firePropertyChange(key, old, value);
405         return old;
406     }
407
408     public boolean containsProperty(String JavaDoc key) {
409         return props.containsKey(key);
410     }
411
412     public Object JavaDoc removeProperty(String JavaDoc key) {
413         //System.err.print("DefaultSession.setProperty");
414
Object JavaDoc old = props.remove(key);
415         propertyChangeSupport.firePropertyChange(key, old, null);
416         return old;
417     }
418
419     private final WeakPropertyChangeSupport propertyChangeSupport =
420             new WeakPropertyChangeSupport(this);
421
422
423     public void addPropertyChangeListener(PropertyChangeListener JavaDoc listener) {
424         propertyChangeSupport.addPropertyChangeListener(listener);
425     }
426
427
428     public void removePropertyChangeListener(PropertyChangeListener JavaDoc listener) {
429         propertyChangeSupport.removePropertyChangeListener(listener);
430     }
431
432     /**
433      * Describe <code>addPropertyChangeListener</code> method here.
434      *
435      * @param propertyName a <code>String</code> value
436      * @param listener a <code>PropertyChangeListener</code> value
437      */

438     public void addPropertyChangeListener(String JavaDoc propertyName,
439                                           PropertyChangeListener JavaDoc listener) {
440         propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
441     }
442
443     /**
444      * Describe <code>removePropertyChangeListener</code> method here.
445      *
446      * @param propertyName a <code>String</code> value
447      * @param listener a <code>PropertyChangeListener</code> value
448      */

449     public void removePropertyChangeListener(String JavaDoc propertyName,
450                                              PropertyChangeListener JavaDoc listener) {
451         propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
452     }
453
454
455     /**
456      * sets a new locale for this session. The locale is <em>only</em> set,
457      * if it is one of the supported locales {@link #setSupportedLocales},
458      * otherwise an IllegalArgumentException is thrown.
459      *
460      * @param l the locale to be associated with this session.
461      * @throws IllegalArgumentException if this locale is not supported, as
462      * predefined with {@link #setSupportedLocales}.
463      */

464     public void setLocale(Locale JavaDoc l) throws IllegalArgumentException JavaDoc {
465         if (l == null || locale.equals(l))
466             return;
467         if (supportedLocales == null ||
468                 supportedLocales.length == 0 ||
469                 Arrays.asList(supportedLocales).contains(l)) {
470             locale = l;
471             propertyChangeSupport.firePropertyChange(LOCALE_PROPERTY, locale, l);
472             log.info("Set Locale " + l);
473         } else
474             throw new IllegalArgumentException JavaDoc("Locale " + l + " not supported");
475     }
476
477     /**
478      * The Locale of the current session. This Locale reflects the Locale of the clients userAgent.
479      *
480      * @return a <code>Locale</code> value
481      */

482     public Locale JavaDoc getLocale() {
483         return locale;
484     }
485
486     /**
487      * Indicates if the wings session servlet should adopt the clients Locale provided by the
488      * browsers in the HTTP header.
489      *
490      * @param adoptLocale if true, try to determine, false ignore
491      */

492     public final void setLocaleFromHeader(boolean adoptLocale) {
493         localeFromHeader = adoptLocale;
494     }
495
496     /**
497      * Indicates if the wings session servlet should adopt the clients Locale provided by the
498      * browsers in the HTTP header.
499      */

500     public final boolean getLocaleFromHeader() {
501         return localeFromHeader;
502     }
503
504
505     /**
506      * sets the locales, supported by this application. If empty or <em>null</em>, all locales are supported.
507      */

508     public final void setSupportedLocales(Locale JavaDoc[] locales) {
509         supportedLocales = locales;
510     }
511
512     /**
513      * Returns the locales, supported by this application. If empty or <em>null</em>, all locales are supported.
514      */

515     public final Locale JavaDoc[] getSupportedLocales() {
516         return supportedLocales;
517     }
518
519
520     /**
521      * The current character encoding used for the communication with the clients userAgent.
522      * If <code>null</code> then the current characterEncoding is determined by the current
523      * session Locale via the charset.properties map.
524      *
525      * @param characterEncoding The charcterEncoding which should be enforces for this session (i.e. "utf-8"),
526      * or <code>null</code> if it should be determined by the clients userAgent Locale.
527      */

528     public void setCharacterEncoding(String JavaDoc characterEncoding) {
529         this.characterEncoding = characterEncoding;
530     }
531
532     /**
533      * The current character encoding used for the communication with the clients userAgent.
534      * If <code>null</code> then the current characterEncoding is determined by the current
535      * session Locale via the charset.properties map.
536      *
537      * @return The characterEncoding set for this sesson or determined by the current Locale.
538      */

539     public String JavaDoc getCharacterEncoding() {
540         if (this.characterEncoding == null) {
541             return LocaleCharSet.getInstance().getCharSet(getLocale());
542         } else {
543             return this.characterEncoding;
544         }
545     }
546
547     private final long getUniqueId() {
548         return uniqueIdCounter++;
549     }
550
551     /**
552      * Creates a session context unique ID, that can be used as an identifier,
553      * i.e. it is guaranteed to start with a letter
554      *
555      * @return a <code>String</code> value
556      */

557     public final String JavaDoc createUniqueId() {
558         return StringUtil.toIdentifierString(getUniqueId());
559     }
560
561     /**
562      * Get the maximum content length (file size) for a post
563      * request.
564      *
565      * @return maximum size in kB (1024 Byte)
566      * @see org.wings.session.MultipartRequest
567      */

568     public final int getMaxContentLength() {
569         return maxContentLength;
570     }
571
572     /**
573      * Set the maximum content length (file size) for a post
574      * request.
575      *
576      * @param l size in kB (1024 Byte)
577      * @see org.wings.session.MultipartRequest
578      */

579     public final void setMaxContentLength(int l) {
580         maxContentLength = l;
581     }
582
583     /**
584      * Describe <code>destroy</code> method here.
585      */

586     protected void destroy() {
587
588         try {
589             firePrepareExit(true);
590         } catch (ExitVetoException ex) {
591             // ignore this, because no veto possible
592
}
593
594         if (collectStatistics) {
595             WingsStatistics.getStatistics().decrementActiveSessionCount();
596         } // end of if ()
597

598
599         Iterator JavaDoc it = frames.iterator();
600         while (it.hasNext()) {
601             SContainer container = ((SFrame) it.next()).getContentPane();
602             if (container != null)
603                 container.removeAll();
604         }
605
606         reloadManager.clear();
607         reloadManager = null;
608         externalizeManager.clear();
609         externalizeManager = null;
610         dispatcher.clear();
611         dispatcher = null;
612
613         frames.clear();
614         props.clear();
615
616
617         Object JavaDoc[] listeners = listenerList.getListenerList();
618         for (int i = listeners.length - 2; i >= 0; i -= 2) {
619             listenerList.remove((Class JavaDoc) listeners[i], (EventListener JavaDoc) listeners[i + 1]);
620         } // end of for (int i=0; i<; i++)
621

622     }
623
624     /**
625      * Exit the current session and redirect to other URL.
626      * <p/>
627      * This removes the session and its associated
628      * application from memory. The userAgent is redirected to the given
629      * URL. Note, that it is not even possible for the user to re-enter
630      * the application with the BACK-button, since all information is
631      * removed.
632      * <p/>
633      * <em>Always</em> exit an application by calling an
634      * <code>exit()</code> method, especially, if it is an application
635      * that requires a login and thus handles sensitive information accessible
636      * through the session. Usually, you will call this on behalf of an
637      * event within an <code>ActionListener.actionPerformed()</code> like for
638      * a pressed 'EXIT'-Button.
639      *
640      * @param redirectAddress the address, the userAgent is redirected after
641      * removing this session. This must be a String
642      * containing the complete URL (no relative URL)
643      * to the place to be redirected. If 'null', nothing
644      * happens.
645      */

646     public void exit(String JavaDoc redirectAddress) {
647         this.exitAddress = redirectAddress;
648     }
649
650     /**
651      * Exit the current session and redirect to new application instance.
652      * <p/>
653      * This removes the session and its associated
654      * application from memory. The userAgent is redirected to the same
655      * application with a fresh session. Note, that it is not even
656      * possible for the user to re-enter the old application with the
657      * BACK-button, since all information is removed.
658      * <p/>
659      * <em>Always</em> exit an application by calling an
660      * <code>exit()</code> method, especially, if it is an application
661      * that requires an login and thus handles sensitive information accessible
662      * through the session. Usually, you will call this on behalf of an
663      * event within an <code>ActionListener.actionPerformed()</code> like for
664      * a pressed 'EXIT'-Button.
665      */

666     public void exit() {
667         exit("");
668     }
669
670     public String JavaDoc getExitAddress() {
671         return exitAddress;
672     }
673
674     public String JavaDoc getRedirectAddress() {
675         return redirectAddress;
676     }
677
678     /**
679      * Describe <code>setRedirectAddress</code> method here.
680      *
681      * @param redirectAddress a <code>String</code> value
682      */

683     public void setRedirectAddress(String JavaDoc redirectAddress) {
684         this.redirectAddress = redirectAddress;
685     }
686
687
688     public void addExitListener(SExitListener listener) {
689         listenerList.add(SExitListener.class,
690                 listener);
691     }
692
693
694     public void removeExitListener(SExitListener listener) {
695         listenerList.remove(SExitListener.class,
696                 listener);
697     }
698
699     /**
700      * Describe <code>getExitListeners</code> method here.
701      *
702      * @return a <code>SExitListener[]</code> value
703      */

704     public SExitListener[] getExitListeners() {
705         return (SExitListener[]) listenerList.getListeners(SExitListener.class);
706     }
707
708
709     /**
710      * Fire an RequestEvent at each registered listener.
711      */

712     final void firePrepareExit() throws ExitVetoException {
713         firePrepareExit(false);
714     }
715
716     final void firePrepareExit(boolean ignoreVeto) throws ExitVetoException {
717         SExitEvent event = null;
718
719         Object JavaDoc[] listeners = listenerList.getListenerList();
720         for (int i = listeners.length - 2; i >= 0; i -= 2) {
721             if (listeners[i] == SExitListener.class) {
722                 // Lazily create the event:
723
if (event == null) {
724                     event = new SExitEvent(this);
725                 }
726                 try {
727                     ((SExitListener) listeners[i + 1]).prepareExit(event);
728                 } catch (ExitVetoException ex) {
729                     if (!ignoreVeto) {
730                         throw ex;
731                     }
732                 }
733             }
734         }
735     }
736
737
738     public void addRequestListener(SRequestListener listener) {
739         listenerList.add(SRequestListener.class, listener);
740     }
741
742
743     public void removeRequestListener(SRequestListener listener) {
744         listenerList.remove(SRequestListener.class, listener);
745     }
746
747     /**
748      * Fire an RequestEvent at each registered listener.
749      */

750     void fireRequestEvent(int type) {
751         fireRequestEvent(type, null);
752     }
753
754     /**
755      * Fire an RequestEvent at each registered listener.
756      */

757     void fireRequestEvent(int type, ExternalizedResource resource) {
758         SRequestEvent event = null;
759
760         Object JavaDoc[] listeners = listenerList.getListenerList();
761         for (int i = listeners.length - 2; i >= 0; i -= 2) {
762             if (listeners[i] == SRequestListener.class) {
763                 // Lazily create the event:
764
if (event == null) {
765                     event = new SRequestEvent(this, type, resource);
766                 }
767                 ((SRequestListener) listeners[i + 1]).processRequest(event);
768             }
769         }
770     }
771
772     protected void finalize() {
773         log.info("gc session");
774         if (collectStatistics) {
775             WingsStatistics.getStatistics().decrementAllocatedSessionCount();
776         } // end of if ()
777
}
778 }
779
780
781
Popular Tags