Source code: org/mortbay/j2ee/session/BindingInterceptor.java
1 // ========================================================================
2 // Copyright (c) 2002 Mort Bay Consulting (Australia) Pty. Ltd.
3 // $Id: BindingInterceptor.java,v 1.2 2003/10/05 14:04:54 gregwilkins Exp $
4 // ========================================================================
5
6 package org.mortbay.j2ee.session;
7
8 //----------------------------------------
9
10 import java.rmi.RemoteException;
11 import javax.servlet.http.HttpSession;
12 import javax.servlet.http.HttpSessionBindingEvent;
13 import javax.servlet.http.HttpSessionBindingListener;
14 import org.jboss.logging.Logger;
15
16 //----------------------------------------
17
18 /**
19 * A <code>BindingInterceptor</code> is responsible for notifying
20 * HttpSessionAttributeListeners when Attributes are added to, removed
21 * from or replaced in a Session and HttpSessionBindingListeners when
22 * attributes are bound into or unbound from a Session. <P/> This is
23 * an expensive Interceptor to use since it requires that on rebinding
24 * an attribute in the Session, the old value is returned in case it
25 * is a Listener requiring notification of it's removal.If you are
26 * using a distributed store, this requirement will result in a
27 * serialisation and network traffic overhead which may not actually
28 * be necessary. Unfortunately it would be expensive to decide at
29 * runtime whether to add this interceptor since one of these
30 * Listeners might be bound into the session at any time from any
31 * node. This may be addressed in a future release.
32 *
33 * @author <a href="mailto:jules@mortbay.com">Jules Gosnell</a>
34 * @version 1.0
35 */
36 public class BindingInterceptor
37 extends StateInterceptor
38 {
39 protected static final Logger _log=Logger.getLogger(BindingInterceptor.class);
40 // All Interceptors are expected to provide this constructor...
41
42 // HttpSessionBindingListeners are held in the SessionManager -
43 // because they are attached at the webapp, rather than session
44 // instance level. So they are notified via the Manager.
45
46 protected Object
47 notifyValueUnbound(String name, Object value)
48 {
49 if (!(value instanceof HttpSessionBindingListener))
50 return value;
51
52 HttpSessionBindingEvent event=new HttpSessionBindingEvent(getSession(), name, value);
53 ((HttpSessionBindingListener)value).valueUnbound(event);
54 event=null;
55
56 return value;
57 }
58
59 protected Object
60 notifyValueBound(String name, Object value)
61 {
62 if (!(value instanceof HttpSessionBindingListener))
63 return value;
64
65 HttpSessionBindingEvent event=new HttpSessionBindingEvent(getSession(), name, value);
66 ((HttpSessionBindingListener)value).valueBound(event);
67 event=null;
68
69 return value;
70 }
71
72 // if we knew whether there were any HttpSessionAttributeListeners
73 // registered with our Manager and the DistributedState knew whether
74 // the oldValue was an HttpSessionBindingListener then we could make
75 // the decision in the e.g. EJB tier as to whether to return the
76 // oldValue or not. Unfortunately, all attributes are preserialised
77 // in the Web Tier, in case the EJB tier doesn't have their class,
78 // so this interceptor would have to mark relevant attributes on
79 // their way into the EJB tier, so it would know whether to return
80 // them in a set/removeAttribute situation later... - How can this
81 // be done efficiently ?
82
83 /**
84 * <code>setAttribute</code> is overriden in order to notify
85 * HttpSessionAttribute and HttpSessionBindingListeners of relative
86 * Attribute changes.
87 *
88 * @param name a <code>String</code> value
89 * @param value an <code>Object</code> value
90 * @return an <code>Object</code> value
91 * @exception RemoteException if an error occurs
92 */
93 public Object
94 setAttribute(String name, Object value, boolean returnValue)
95 throws RemoteException
96 {
97 // assert(name!=null);
98 // assert(value!=null);
99
100 boolean needOldValue=true;
101
102 // we want the old binding back if it was an HttpSessionBindingListener
103 Object oldValue=super.setAttribute(name, value, true);
104
105 // send binding notifications
106
107 try
108 {
109 if (oldValue!=null)
110 notifyValueUnbound(name, oldValue);
111
112 notifyValueBound(name, value);
113
114 // send attribute notifications
115 if (oldValue!=null)
116 getManager().notifyAttributeReplaced(getSession(), name, oldValue);
117 else
118 getManager().notifyAttributeAdded(getSession(), name, value);
119 }
120 catch (Throwable t)
121 {
122 _log.error("error in user owned Listener - notifications may be incomplete", t);
123 }
124
125 return oldValue;
126 }
127
128 /**
129 * <code>removeAttribute</code> is overriden in order to notify
130 * HttpSessionAttribute and HttpSessionBindingListeners of relative
131 * Attribute changes.
132 *
133 * @param name a <code>String</code> value
134 * @return an <code>Object</code> value
135 * @exception RemoteException if an error occurs
136 */
137 public Object
138 removeAttribute(String name, boolean returnValue)
139 throws RemoteException
140 {
141 // we want the old binding back if it was an HttpSessionBindingListener
142 Object oldValue=super.removeAttribute(name, true);
143
144 if (oldValue!=null)
145 {
146 try
147 {
148 notifyValueUnbound(name, oldValue);
149 getManager().notifyAttributeRemoved(getSession(), name, oldValue);
150 }
151 catch (Throwable t)
152 {
153 _log.error("error in user owned Listener - notifications may be incomplete", t);
154 }
155 }
156
157 return oldValue;
158 }
159
160 // public Object clone() { return null; } // Stateful
161 }