KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > web > tomcat > tc5 > session > ClusteredSession


1 /*
2  * JBoss, the OpenSource WebOS
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7 package org.jboss.web.tomcat.tc5.session;
8
9 import org.apache.catalina.Manager;
10 import org.apache.catalina.Context;
11 import org.apache.catalina.Session;
12
13 import java.io.IOException JavaDoc;
14 import java.io.Serializable JavaDoc;
15 import java.util.Enumeration JavaDoc;
16 import java.util.Map JavaDoc;
17
18 import org.apache.catalina.util.StringManager;
19 import org.apache.catalina.util.Enumerator;
20 import org.apache.catalina.session.StandardSession;
21 import org.jboss.logging.Logger;
22
23 import javax.servlet.http.*;
24
25 /**
26  * Abstract base class for session clustering based on StandardSession. Different session
27  * replication strategy can be implemented such as session- or attribute-based ones.
28  *
29  * @author Ben Wang
30  * @version $Revision: 1.5.2.8 $
31  */

32 abstract class ClusteredSession
33    extends StandardSession
34 {
35    private static final long serialVersionUID = -758573655613558722L;
36    protected static Logger log = Logger.getLogger(ClusteredSession.class);
37
38    // ----------------------------------------------------- Instance Variables
39
/**
40     * Descriptive information describing this Session implementation.
41     */

42    protected static final String JavaDoc info = "ClusteredSession/1.0";
43
44    protected int invalidationPolicy;
45
46    /**
47     * If true, it means the in-memory session data is not in sync with that in the data store.
48     */

49    protected transient boolean isOutdated;
50
51    /**
52     * Version number to track cache invalidation. If any new version number is greater than this
53     * one, it means the data it holds is newer than this one.
54     */

55    protected int version;
56
57    /**
58     * The string manager for this package.
59     */

60    protected static StringManager sm =
61       StringManager.getManager("org.jboss.web.tomcat.session");
62
63    public ClusteredSession(AbstractJBossManager manager)
64    {
65       super(manager);
66       invalidationPolicy = ((AbstractJBossManager) this.manager).getInvalidateSessionPolicy();
67       isOutdated = false;
68       version = 0;
69    }
70
71    /**
72     * Check to see if the session data is still valid. Outdated here means that the in-memory data is
73     * not in sync with one in the data store.
74     * @return
75     */

76    public boolean isOutdated()
77    {
78       return isOutdated;
79    }
80
81    public void setIsOutdated(boolean outdated)
82    {
83       isOutdated = outdated;
84    }
85
86    /**
87     * Check to see if the input version number is greater than I am. If it is, it means we will
88     * need to invalidate the in-memory cache.
89     * @param version
90     * @return
91     */

92    public boolean isNewData(int version)
93    {
94       return (this.version < version) ? true: false;
95    }
96
97    public int getVersion()
98    {
99       return version;
100    }
101
102    /**
103     * There are couple ways to generate this version number. But we will stick with the simple one
104     * for now.
105     * @return
106     */

107    public int incrementVersion()
108    {
109       return version++;
110    }
111
112    /**
113     * This is called after loading a session to initialize the transient values.
114     *
115     * @param manager
116     */

117    public abstract void initAfterLoad(AbstractJBossManager manager);
118
119    /**
120     * Set the Manager within which this Session is valid.
121     *
122     * @param manager The new Manager
123     */

124    public void setManager(Manager manager)
125    {
126
127       super.setManager(manager);
128
129       this.manager = manager;
130    }
131
132    /**
133     * Propogate session to the internal store.
134     */

135    public abstract void processSessionRepl();
136
137    /**
138     * Remove myself from the internal store.
139     */

140    public abstract void removeMyself();
141
142    /**
143     * Remove myself from the <t>local</t> internal store.
144     */

145    public abstract void removeMyselfLocal();
146
147    //
148
// ------------------------------------------------- Session Public Methods
149

150    public Object JavaDoc getAttribute(String JavaDoc name)
151    {
152
153       if (!isValid())
154          throw new IllegalStateException JavaDoc
155             (sm.getString("clusteredSession.getAttribute.ise"));
156
157       return getAttributeInternal(name);
158    }
159
160    public Enumeration JavaDoc getAttributeNames()
161    {
162       if (!isValid())
163          throw new IllegalStateException JavaDoc
164             (sm.getString("clusteredSession.getAttributeNames.ise"));
165
166       return (new Enumerator(getAttributesInternal().keySet(), true));
167    }
168
169    public void setAttribute(String JavaDoc name, Object JavaDoc value)
170    {
171       // Name cannot be null
172
if (name == null)
173          throw new IllegalArgumentException JavaDoc
174             (sm.getString("clusteredSession.setAttribute.namenull"));
175
176       // Null value is the same as removeAttribute()
177
if (value == null)
178       {
179          removeAttribute(name);
180          return;
181       }
182
183       // Validate our current state
184
if (!isValid())
185          throw new IllegalStateException JavaDoc
186             (sm.getString("clusteredSession.setAttribute.ise"));
187       if ((manager != null) && manager.getDistributable() &&
188          !(value instanceof Serializable JavaDoc))
189          throw new IllegalArgumentException JavaDoc
190             (sm.getString("clusteredSession.setAttribute.iae"));
191
192       // Construct an event with the new value
193
HttpSessionBindingEvent event = null;
194
195       // Call the valueBound() method if necessary
196
if (value instanceof HttpSessionBindingListener)
197       {
198          event = new HttpSessionBindingEvent(getSession(), name, value);
199          try
200          {
201             ((HttpSessionBindingListener) value).valueBound(event);
202          }
203          catch (Throwable JavaDoc t)
204          {
205              manager.getContainer().getLogger().error(sm.getString("standardSession.bindingEvent"), t);
206          }
207       }
208
209       // Replace or add this attribute
210
Object JavaDoc unbound = setInternalAttribute(name, value);
211
212       // Call the valueUnbound() method if necessary
213
if ((unbound != null) &&
214          (unbound instanceof HttpSessionBindingListener))
215       {
216          try
217          {
218             ((HttpSessionBindingListener) unbound).valueUnbound
219                (new HttpSessionBindingEvent(getSession(), name));
220          }
221          catch (Throwable JavaDoc t)
222          {
223              manager.getContainer().getLogger().error(sm.getString("standardSession.bindingEvent"), t);
224          }
225       }
226
227       // Notify interested application event listeners
228
Context context = (Context) manager.getContainer();
229       Object JavaDoc listeners[] = context.getApplicationEventListeners();
230       if (listeners == null)
231          return;
232       for (int i = 0; i < listeners.length; i++)
233       {
234          if (!(listeners[i] instanceof HttpSessionAttributeListener))
235             continue;
236          HttpSessionAttributeListener listener =
237             (HttpSessionAttributeListener) listeners[i];
238          try
239          {
240             if (unbound != null)
241             {
242                fireContainerEvent(context,
243                   "beforeSessionAttributeReplaced",
244                   listener);
245                if (event == null)
246                {
247                   event = new HttpSessionBindingEvent
248                      (getSession(), name, unbound);
249                }
250                listener.attributeReplaced(event);
251                fireContainerEvent(context,
252                   "afterSessionAttributeReplaced",
253                   listener);
254             }
255             else
256             {
257                fireContainerEvent(context,
258                   "beforeSessionAttributeAdded",
259                   listener);
260                if (event == null)
261                {
262                   event = new HttpSessionBindingEvent
263                      (getSession(), name, value);
264                }
265                listener.attributeAdded(event);
266                fireContainerEvent(context,
267                   "afterSessionAttributeAdded",
268                   listener);
269             }
270          }
271          catch (Throwable JavaDoc t)
272          {
273             try
274             {
275                if (unbound != null)
276                {
277                   fireContainerEvent(context,
278                      "afterSessionAttributeReplaced",
279                      listener);
280                }
281                else
282                {
283                   fireContainerEvent(context,
284                      "afterSessionAttributeAdded",
285                      listener);
286                }
287             }
288             catch (Exception JavaDoc e)
289             {
290                ;
291             }
292             manager.getContainer().getLogger().error(sm.getString("standardSession.attributeEvent"), t);
293          }
294       }
295
296    }
297
298
299    /**
300     * Invalidates this session and unbinds any objects bound to it.
301     * Override here to remove across the cluster instead of just expiring.
302     *
303     * @exception IllegalStateException if this method is called on
304     * an invalidated session
305     */

306    public void invalidate()
307    {
308      if (!isValid())
309         throw new IllegalStateException JavaDoc
310            (sm.getString("clusteredSession.invalidate.ise"));
311
312      // Cause this session to expire globally
313
boolean notify = true;
314      boolean expireLocally = false;
315      expire(notify, expireLocally);
316    }
317
318   /**
319    * Override here to reverse the order of manager session removal and
320    * attribute removal.
321    *
322    * @param notify
323    */

324   public void expire(boolean notify)
325   {
326      boolean expireLocally = true;
327      expire(notify, expireLocally);
328   }
329
330   protected void expire(boolean notify, boolean expireLocally)
331   {
332       if (log.isDebugEnabled())
333       {
334          log.debug("The session has expired with id: " + id + " is it local? " +expireLocally);
335       }
336       // Mark this session as "being expired" if needed
337
if (expiring)
338          return;
339
340       synchronized (this)
341       {
342
343          if (manager == null)
344             return;
345
346          expiring = true;
347
348          // Notify interested application event listeners
349
// FIXME - Assumes we call listeners in reverse order
350
Context context = (Context) manager.getContainer();
351          Object JavaDoc listeners[] = context.getApplicationLifecycleListeners();
352          if (notify && (listeners != null))
353          {
354             HttpSessionEvent event =
355                new HttpSessionEvent(getSession());
356             for (int i = 0; i < listeners.length; i++)
357             {
358                int j = (listeners.length - 1) - i;
359                if (!(listeners[j] instanceof HttpSessionListener))
360                   continue;
361                HttpSessionListener listener =
362                   (HttpSessionListener) listeners[j];
363                try
364                {
365                   fireContainerEvent(context,
366                      "beforeSessionDestroyed",
367                      listener);
368                   listener.sessionDestroyed(event);
369                   fireContainerEvent(context,
370                      "afterSessionDestroyed",
371                      listener);
372                }
373                catch (Throwable JavaDoc t)
374                {
375                   try
376                   {
377                      fireContainerEvent(context,
378                         "afterSessionDestroyed",
379                         listener);
380                   }
381                   catch (Exception JavaDoc e)
382                   {
383                      ;
384                   }
385                   manager.getContainer().getLogger().error(sm.getString("standardSession.sessionEvent"), t);
386                }
387             }
388          }
389
390          // Notify interested session event listeners
391
if (notify)
392          {
393             fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null);
394          }
395
396          // Bug fix JBAS-1360
397
// Unbind any objects associated with this session
398
String JavaDoc keys[] = keys();
399          for (int i = 0; i < keys.length; i++)
400              removeAttributeInternal(keys[i], notify);
401
402          // Remove this session from our manager's active sessions
403
if (manager != null)
404          {
405             if(expireLocally)
406             {
407                 ((AbstractJBossManager) manager).removeLocal(this);
408             } else
409             {
410                ((AbstractJBossManager) manager).remove(this);
411             }
412          }
413
414          // We have completed expire of this session
415
accessCount = 0;
416          setValid(false);
417          expiring = false;
418
419       }
420    }
421
422    public void passivate()
423    {
424       // TODO. We don't do this now.
425
}
426
427    public void activate()
428    {
429       // TODO. We don't do this now.
430
}
431
432    // ------------------------------------------------ Internal protected method override
433

434    /**
435     * Method inherited from Tomcat. Return zero-length based string if not found.
436     */

437    protected String JavaDoc[] keys()
438    {
439       return ((String JavaDoc[]) getAttributesInternal().keySet().toArray(EMPTY_ARRAY));
440    }
441
442    protected void removeAttributeInternal(String JavaDoc name, boolean notify)
443    {
444
445       // Remove this attribute from our collection
446
Object JavaDoc value = removeJBossInternalAttribute(name);
447
448       // Do we need to do valueUnbound() and attributeRemoved() notification?
449
if (!notify || (value == null))
450       {
451          return;
452       }
453
454       // Call the valueUnbound() method if necessary
455
HttpSessionBindingEvent event = null;
456       if (value instanceof HttpSessionBindingListener)
457       {
458          event = new HttpSessionBindingEvent(getSession(), name, value);
459          ((HttpSessionBindingListener) value).valueUnbound(event);
460       }
461
462       // Notify interested application event listeners
463
Context context = (Context) manager.getContainer();
464       Object JavaDoc listeners[] = context.getApplicationEventListeners();
465       if (listeners == null)
466          return;
467       for (int i = 0; i < listeners.length; i++)
468       {
469          if (!(listeners[i] instanceof HttpSessionAttributeListener))
470             continue;
471          HttpSessionAttributeListener listener =
472             (HttpSessionAttributeListener) listeners[i];
473          try
474          {
475             fireContainerEvent(context,
476                "beforeSessionAttributeRemoved",
477                listener);
478             if (event == null)
479             {
480                event = new HttpSessionBindingEvent
481                   (getSession(), name, value);
482             }
483             listener.attributeRemoved(event);
484             fireContainerEvent(context,
485                "afterSessionAttributeRemoved",
486                listener);
487          }
488          catch (Throwable JavaDoc t)
489          {
490             try
491             {
492                fireContainerEvent(context,
493                   "afterSessionAttributeRemoved",
494                   listener);
495             }
496             catch (Exception JavaDoc e)
497             {
498                ;
499             }
500             manager.getContainer().getLogger().error(sm.getString("standardSession.attributeEvent"), t);
501          }
502       }
503
504    }
505
506    protected Object JavaDoc getAttributeInternal(String JavaDoc name)
507    {
508       return getJBossInternalAttribute(name);
509    }
510
511    protected Map JavaDoc getAttributesInternal()
512    {
513       return getJBossInternalAttributes();
514    }
515
516    protected Object JavaDoc setInternalAttribute(String JavaDoc name, Object JavaDoc value)
517    {
518       return setJBossInternalAttribute(name, value);
519    }
520
521    // ------------------------------------------------ JBoss internal abstract method
522
protected abstract Object JavaDoc getJBossInternalAttribute(String JavaDoc name);
523
524    protected abstract Object JavaDoc removeJBossInternalAttribute(String JavaDoc name);
525
526    protected abstract Map JavaDoc getJBossInternalAttributes();
527
528    protected abstract Object JavaDoc setJBossInternalAttribute(String JavaDoc name, Object JavaDoc value);
529
530    // ------------------------------------------------ Session Package Methods
531
protected void writeObject(java.io.ObjectOutputStream JavaDoc out)
532       throws IOException JavaDoc
533    {
534       synchronized (attributes)
535       {
536          out.defaultWriteObject();
537       }
538    }
539
540    protected void readObject(java.io.ObjectInputStream JavaDoc in)
541       throws IOException JavaDoc, ClassNotFoundException JavaDoc
542    {
543       in.defaultReadObject();
544    }
545
546 }
547
Popular Tags