KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > web > tomcat > tc6 > session > SessionReplicationContext


1 package org.jboss.web.tomcat.tc6.session;
2
3 import java.util.HashMap JavaDoc;
4 import java.util.Map JavaDoc;
5
6 import org.apache.catalina.connector.Request;
7 import org.apache.catalina.connector.Response;
8
9 public final class SessionReplicationContext
10 {
11    private static final ThreadLocal JavaDoc replicationContext = new ThreadLocal JavaDoc();
12    
13    private static final SessionReplicationContext EMPTY = new SessionReplicationContext();
14    
15    private int webappCount;
16    private int activityCount;
17    private SnapshotManager soleManager;
18    private ClusteredSession soleSession;
19    private Map JavaDoc crossCtxSessions;
20    private Map JavaDoc expiredSessions;
21    private Request outerRequest;
22    private Response outerResponse;
23    
24    /**
25     * Associate a SessionReplicationContext with the current thread, if
26     * there isn't one already. If there isn't one, associate the
27     * given request and response with the context.
28     * <p/>
29     * <strong>NOTE:</strong> Nested calls to this method and {@link #exitWebapp()}
30     * are supported; once a context is established the number of calls to this
31     * method and <code>exitWebapp()</code> are tracked.
32     *
33     * @param request
34     * @param response
35     */

36    public static void enterWebapp(Request request, Response response, boolean startCacheActivity)
37    {
38       SessionReplicationContext ctx = getCurrentContext();
39       if (ctx == null)
40       {
41          ctx = new SessionReplicationContext(request, response);
42          replicationContext.set(ctx);
43       }
44       
45       ctx.webappCount++;
46       if (startCacheActivity)
47          ctx.activityCount++;
48    }
49    
50    /**
51     * Signals that the webapp is finished handling the request (and
52     * therefore replication can begin.)
53     *
54     * @return a SessionReplicationContext, from which information
55     * about any sessions needing replication can be obtained.
56     * Will not return <code>null</code>.
57     */

58    public static SessionReplicationContext exitWebapp()
59    {
60       SessionReplicationContext ctx = getCurrentContext();
61       if (ctx != null)
62       {
63          ctx.webappCount--;
64          if (ctx.webappCount < 1)
65          {
66             // We've unwound any nested webapp calls, so we'll clean up and
67
// return the context to allow replication. If all cache activity
68
// is done as well, clear the ThreadLocal
69

70             ctx.outerRequest = null;
71             ctx.outerResponse = null;
72             
73             if (ctx.activityCount < 1)
74                replicationContext.set(null);
75             
76             return ctx;
77          }
78       }
79       
80       // A nested valve called us. Just return an empty context
81
return EMPTY;
82       
83    }
84    
85    public static void bindSession(ClusteredSession session, SnapshotManager manager)
86    {
87       SessionReplicationContext ctx = getCurrentContext();
88       if (ctx != null && ctx.webappCount > 0)
89       {
90          ctx.addReplicatableSession(session, manager);
91       }
92       /*else {
93          We are past the part of the request cycle where we
94          track sessions for replication
95       }*/

96    }
97    
98    public static void sessionExpired(ClusteredSession session, String JavaDoc realId, SnapshotManager manager)
99    {
100       SessionReplicationContext ctx = getCurrentContext();
101       if (ctx != null && ctx.webappCount > 0)
102       {
103          ctx.addExpiredSession(session, manager);
104       }
105    }
106    
107    public static boolean isSessionBoundAndExpired(String JavaDoc realId, SnapshotManager manager)
108    {
109       boolean result = false;
110       SessionReplicationContext ctx = getCurrentContext();
111       if (ctx != null)
112       {
113          result = ctx.isSessionExpired(realId, manager);
114       }
115       return result;
116    }
117    
118    /**
119     * Marks the current thread as actively processing the given session.
120     * If the thread has already been so marked, increases a counter
121     * so a subsequent call to finishLocalActivity does not remove
122     * the association (allowing nested calls).
123     */

124    public static void startCacheActivity()
125    {
126       SessionReplicationContext ctx = getCurrentContext();
127       if (ctx == null)
128       {
129          ctx = new SessionReplicationContext();
130          replicationContext.set(ctx);
131       }
132       
133       ctx.activityCount++;
134    }
135    
136    /**
137     * Marks the completion of activity on a given session. Should be called
138     * once for each invocation of {@link #startCacheActivity()}.
139     */

140    public static void finishCacheActivity()
141    {
142       SessionReplicationContext ctx = getCurrentContext();
143       if (ctx != null)
144       {
145          ctx.activityCount--;
146          if (ctx.activityCount < 1 && ctx.webappCount < 1)
147          {
148             replicationContext.set(null);
149          }
150       }
151    }
152    
153    public static boolean isLocallyActive()
154    {
155       return getCurrentContext() != null;
156    }
157    
158    public static Request getOriginalRequest()
159    {
160       SessionReplicationContext ctx = getCurrentContext();
161       return (ctx == null ? null : ctx.outerRequest);
162    }
163    
164    public static Response getOriginalResponse()
165    {
166       SessionReplicationContext ctx = getCurrentContext();
167       return (ctx == null ? null : ctx.outerResponse);
168    }
169    
170    private static SessionReplicationContext getCurrentContext()
171    {
172       return (SessionReplicationContext) replicationContext.get();
173    }
174    
175    private SessionReplicationContext(Request request, Response response)
176    {
177       this.outerRequest = request;
178       this.outerResponse = response;
179    }
180    
181    private SessionReplicationContext() {}
182
183    /**
184     * Gets a Map<SnapshotManager, ClusteredSession> of sessions that were accessed
185     * during the course of a request. Will only be non-null if
186     * {@link #bindSession(ClusteredSession, SnapshotManager)} was called
187     * with more than one SnapshotManager (i.e the request crossed session
188     * contexts.)
189     */

190    public Map JavaDoc getCrossContextSessions()
191    {
192       return crossCtxSessions;
193    }
194
195    /**
196     * Gets the SnapshotManager that was passed to
197     * {@link #bindSession(ClusteredSession, SnapshotManager)} if and only
198     * if only one such SnapshotManager was passed. Returns <code>null</code>
199     * otherwise, in which case a cross-context request is a possibility,
200     * and {@link #getCrossContextSessions()} should be checked.
201     */

202    public SnapshotManager getSoleSnapshotManager()
203    {
204       return soleManager;
205    }
206
207    /**
208     * Gets the ClusteredSession that was passed to
209     * {@link #bindSession(ClusteredSession, SnapshotManager)} if and only
210     * if only one SnapshotManager was passed. Returns <code>null</code>
211     * otherwise, in which case a cross-context request is a possibility,
212     * and {@link #getCrossContextSessions()} should be checked.
213     */

214    public ClusteredSession getSoleSession()
215    {
216       return soleSession;
217    }
218    
219    private void addReplicatableSession(ClusteredSession session, SnapshotManager mgr)
220    {
221       if (crossCtxSessions != null)
222       {
223          crossCtxSessions.put(session, mgr);
224       }
225       else if (soleManager == null)
226       {
227          // First one bound
228
soleManager = mgr;
229          soleSession = session;
230       }
231       else if (!mgr.equals(soleManager))
232       {
233          // We have a cross-context call; need a Map for the sessions
234
crossCtxSessions = new HashMap JavaDoc();
235          crossCtxSessions.put(soleSession, soleManager);
236          crossCtxSessions.put(session, mgr);
237          soleManager = null;
238          soleSession = null;
239       }
240       else
241       {
242          soleSession = session;
243       }
244    }
245    
246    private void addExpiredSession(ClusteredSession session, SnapshotManager manager)
247    {
248       boolean store = manager.equals(soleManager);
249       if (store)
250       {
251          soleManager = null;
252          soleSession = null;
253       }
254       else if (crossCtxSessions != null)
255       {
256          // Only store the session if it was previously in our map
257
store = (crossCtxSessions.remove(session) != null);
258       }
259       
260       if (store)
261       {
262          if (this.expiredSessions == null)
263          {
264             expiredSessions = new HashMap JavaDoc();
265          }
266          expiredSessions.put(manager, session.getRealId());
267       }
268    }
269    
270    private boolean isSessionExpired(String JavaDoc realId, SnapshotManager manager)
271    {
272       boolean result = false;
273       if (expiredSessions != null)
274       {
275          result = realId.equals(expiredSessions.get(manager));
276       }
277       return result;
278    }
279    
280 }
281
Popular Tags