KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mortbay > j2ee > session > AbstractReplicatedStore


1 // ========================================================================
2
// $Id: AbstractReplicatedStore.java,v 1.5 2004/06/22 16:23:44 jules_gosnell Exp $
3
// Copyright 2002-2004 Mort Bay Consulting Pty. Ltd.
4
// ------------------------------------------------------------------------
5
// Licensed under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
// http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
// ========================================================================
15

16 package org.mortbay.j2ee.session;
17
18 //----------------------------------------
19

20 import java.lang.reflect.Method JavaDoc;
21 import java.util.ArrayList JavaDoc;
22 import java.util.Collection JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.Map JavaDoc;
26
27 import org.jfox.ioc.logger.Logger;
28
29 //----------------------------------------
30

31 // implement scavenging
32
// implement setMaxInactiveInterval
33
// look for NYI/TODO
34

35 // this infrastructure could probably be used across JMS aswell -
36
// think about it...
37

38 /**
39  * Maintain synchronisation with other States representing the same
40  * session by publishing changes made to ourself and updating ourself
41  * according to notifications published by the other State objects.
42  *
43  * @author <a HREF="mailto:jules@mortbay.com">Jules Gosnell</a>
44  * @version 1.0
45  */

46
47 abstract public class
48   AbstractReplicatedStore
49   extends AbstractStore
50 {
51   protected final static Logger _log=Logger.getLogger(AbstractReplicatedStore.class);
52
53   protected ClassLoader JavaDoc _loader;
54
55   public
56     AbstractReplicatedStore()
57     {
58       super();
59       _loader=Thread.currentThread().getContextClassLoader();
60     }
61
62   public ClassLoader JavaDoc getLoader() {return _loader;}
63   public void setLoader(ClassLoader JavaDoc loader) {_loader=loader;}
64
65   //----------------------------------------
66
// tmp hack to prevent infinite loop
67
private final static ThreadLocal JavaDoc _replicating=new ThreadLocal JavaDoc();
68   public static boolean getReplicating() {return _replicating.get()==Boolean.TRUE;}
69   public static void setReplicating(boolean replicating) {_replicating.set(replicating?Boolean.TRUE:Boolean.FALSE);}
70   //----------------------------------------
71

72   public Object JavaDoc
73     clone()
74     {
75       AbstractReplicatedStore ars=(AbstractReplicatedStore)super.clone();
76       ars.setLoader(getLoader());
77       return ars;
78     }
79
80   protected Map JavaDoc _sessions=new HashMap JavaDoc();
81
82   public int
83     getSessions()
84     {
85       return _sessions.size();
86     }
87
88   //----------------------------------------
89
// Store API - Store LifeCycle
90

91   public void
92     destroy() // corresponds to ctor
93
{
94       _log.trace("destroying...");
95       _sessions.clear();
96       _sessions=null;
97       setManager(null);
98       super.destroy();
99       _log.trace("...destroyed");
100     }
101
102   //----------------------------------------
103
// Store API - State LifeCycle
104

105   public State
106     newState(String JavaDoc id, int maxInactiveInterval)
107     throws Exception JavaDoc
108     {
109       long creationTime=System.currentTimeMillis();
110
111       if (!AbstractReplicatedStore.getReplicating())
112       {
113     Object JavaDoc[] argInstances = {id, new Long JavaDoc(creationTime), new Integer JavaDoc(maxInactiveInterval), new Integer JavaDoc(_actualMaxInactiveInterval)};
114     publish(null, CREATE_SESSION, argInstances);
115       }
116
117       createSession(id, creationTime, maxInactiveInterval, _actualMaxInactiveInterval);
118
119       // if we get one - all we have to do is loadState - because we
120
// will have just created it...
121
return loadState(id);
122     }
123
124   public State
125     loadState(String JavaDoc id)
126     {
127       // pull it out of our cache - if it is not there, it doesn't
128
// exist/hasn't been distributed...
129

130       Object JavaDoc tmp;
131       synchronized (_sessions) {tmp=_sessions.get(id);}
132       return (State)tmp;
133     }
134
135   public void
136     storeState(State state)
137     {
138       try
139       {
140     String JavaDoc id=state.getId();
141     synchronized (_sessions){_sessions.put(id, state);}
142       }
143       catch (Exception JavaDoc e)
144       {
145     _log.error("error storing session", e);
146       }
147     }
148
149   public void
150     removeState(State state)
151     throws Exception JavaDoc
152     {
153       String JavaDoc id=state.getId();
154
155       if (!AbstractReplicatedStore.getReplicating())
156       {
157     Object JavaDoc[] argInstances = {id};
158     publish(null, DESTROY_SESSION, argInstances);
159       }
160
161       destroySession(id);
162     }
163
164   //----------------------------------------
165
// Store API - garbage collection
166

167   public void
168     scavenge()
169     throws Exception JavaDoc
170     {
171       _log.trace("starting distributed scavenging...");
172       Collection JavaDoc copy;
173       synchronized (_sessions) { copy=new ArrayList JavaDoc(_sessions.values()); }
174       if (_log.isTraceEnabled())
175       {
176         int n;
177         synchronized (_subscribers) { n = _subscribers.size(); }
178         _log.trace(copy.size()+" distributed sessions, "+n+" subscribers");
179       }
180       int n = 0;
181       for (Iterator JavaDoc i = copy.iterator(); i.hasNext(); )
182       {
183         LocalState state = (LocalState) i.next();
184         if (! state.isValid(_scavengerExtraTime))
185       {
186             String JavaDoc id = state.getId();
187             if (_log.isDebugEnabled()) _log.debug("scavenging distributed session "+id);
188             destroySession(id);
189         i.remove();
190             ++n;
191       }
192       }
193      if (_log.isTraceEnabled()) _log.trace("scavenged "+n+" distributed sessions");
194      _log.trace("...finished distributed scavenging");
195     }
196
197   //----------------------------------------
198
// Store API - hacks... - NYI/TODO
199

200   public void passivateSession(StateAdaptor sa) {}
201   public boolean isDistributed() {return true;}
202
203   //----------------------------------------
204
// utils
205

206   public String JavaDoc
207     getContextPath()
208     {
209       return getManager().getContextPath();
210     }
211
212   //----------------------------------------
213
// change notification API
214

215   protected static Map JavaDoc _methodToInteger=new HashMap JavaDoc();
216   protected static Method JavaDoc[] _integerToMethod=new Method JavaDoc[8];
217   protected static Method JavaDoc CREATE_SESSION;
218   protected static Method JavaDoc DESTROY_SESSION;
219   protected static Method JavaDoc TOUCH_SESSIONS;
220   protected static Method JavaDoc SET_LAST_ACCESSED_TIME;
221
222   static
223   {
224     // this is absolutely horrible and will break if anyone changes
225
// the shape of the interface - but it is a quick, easy and
226
// efficient hack - so I am using it while I think of a better
227
// way...
228
try
229     {
230       int index=0;
231       Method JavaDoc m=null;
232
233       // class methods...
234
m=CREATE_SESSION=AbstractReplicatedStore.class.getMethod("createSession", new Class JavaDoc[]{String JavaDoc.class, Long.TYPE, Integer.TYPE, Integer.TYPE});
235       _integerToMethod[index]=m;
236       _methodToInteger.put(m.getName(), new Integer JavaDoc(index));
237       index++;
238
239       m=DESTROY_SESSION=AbstractReplicatedStore.class.getMethod("destroySession", new Class JavaDoc[]{String JavaDoc.class});
240       _integerToMethod[index]=m;
241       _methodToInteger.put(m.getName(), new Integer JavaDoc(index));
242       index++;
243
244       m=TOUCH_SESSIONS=AbstractReplicatedStore.class.getMethod("touchSessions", new Class JavaDoc[]{String JavaDoc[].class, Long.TYPE});
245       _integerToMethod[index]=m;
246       _methodToInteger.put(m.getName(), new Integer JavaDoc(index));
247       index++;
248
249       // instance methods...
250
m=SET_LAST_ACCESSED_TIME=State.class.getMethod("setLastAccessedTime", new Class JavaDoc[]{Long.TYPE});
251       _integerToMethod[index]=m;
252       _methodToInteger.put(m.getName(), new Integer JavaDoc(index));
253       index++;
254
255       m=State.class.getMethod("setMaxInactiveInterval", new Class JavaDoc[]{Integer.TYPE});
256       _integerToMethod[index]=m;
257       _methodToInteger.put(m.getName(), new Integer JavaDoc(index));
258       index++;
259
260       m=State.class.getMethod("setAttribute", new Class JavaDoc[]{String JavaDoc.class, Object JavaDoc.class, Boolean.TYPE});
261       _integerToMethod[index]=m;
262       _methodToInteger.put(m.getName(), new Integer JavaDoc(index));
263       index++;
264
265       m=State.class.getMethod("setAttributes", new Class JavaDoc[]{Map JavaDoc.class});
266       _integerToMethod[index]=m;
267       _methodToInteger.put(m.getName(), new Integer JavaDoc(index));
268       index++;
269
270       m=State.class.getMethod("removeAttribute", new Class JavaDoc[]{String JavaDoc.class, Boolean.TYPE});
271       _integerToMethod[index]=m;
272       _methodToInteger.put(m.getName(), new Integer JavaDoc(index));
273       index++;
274     }
275     catch (Exception JavaDoc e)
276     {
277       System.err.println("AbstractReplicatedStore: something went wrong building dispatch tables");
278       e.printStackTrace(System.err);
279     }
280   }
281
282   abstract protected void publish(String JavaDoc id, Method JavaDoc method, Object JavaDoc[] argInstances);
283
284   protected void
285     dispatch(String JavaDoc id, Integer JavaDoc methodId, Object JavaDoc[] argInstances)
286     {
287       try
288       {
289     AbstractReplicatedStore.setReplicating(true);
290
291     Object JavaDoc target=null;
292     if (id==null)
293     {
294       // either this is a class method
295
target=this;
296     }
297     else
298     {
299       // or an instance method..
300
synchronized (_subscribers){target=_subscribers.get(id);}
301     }
302
303     try
304     {
305       Method JavaDoc method=_integerToMethod[methodId.intValue()];
306       if (target==null)
307               _log.warn("null target for "+method);
308           else
309               method.invoke(target, argInstances);
310     }
311     catch (Exception JavaDoc e)
312     {
313       _log.error("this should never happen - code version mismatch ?", e);
314     }
315       }
316       finally
317       {
318     AbstractReplicatedStore.setReplicating(false);
319       }
320     }
321
322   public void
323     createSession(String JavaDoc id, long creationTime, int maxInactiveInterval, int actualMaxInactiveInterval)
324     {
325       if (_log.isTraceEnabled()) _log.trace("creating replicated session: "+id);
326       State state=new LocalState(id, creationTime, maxInactiveInterval, actualMaxInactiveInterval);
327       synchronized(_sessions) {_sessions.put(id, state);}
328
329       if (AbstractReplicatedStore.getReplicating())
330       {
331     // _log.info("trying to promote replicated session");
332
getManager().getHttpSession(id); // should cause creation of corresponding InterceptorStack
333
}
334     }
335
336   public void
337     destroySession(String JavaDoc id)
338     {
339       if (_log.isTraceEnabled()) _log.trace("destroying replicated session: "+id);
340       if(getManager().sessionExists(id))
341           getManager().destroySession(getManager().getHttpSession(id));
342       synchronized(_sessions) {_sessions.remove(id);}
343     }
344
345   public void
346     touchSessions(String JavaDoc[] ids, long time)
347     {
348       // _log.info("touching sessions...: "+ids);
349
for (int i=0;i<ids.length;i++)
350       {
351     String JavaDoc id=ids[i];
352     Object JavaDoc target;
353     // I could synch the whole block. This is slower, but will not
354
// hold up everything else...
355
synchronized (_subscribers){target=_subscribers.get(id);}
356     try
357     {
358       ((StateInterceptor)target).setLastAccessedTime(time);
359     }
360     catch (Exception JavaDoc e)
361     {
362       _log.warn("unable to touch session: "+id+" probably already removed");
363     }
364       }
365     }
366
367   //----------------------------------------
368
// subscription - Listener management...
369

370   protected Map JavaDoc _subscribers=new HashMap JavaDoc();
371
372   public void
373     subscribe(String JavaDoc id, Object JavaDoc o)
374     {
375       _log.trace("subscribing: "+id);
376       synchronized (_subscribers) {_subscribers.put(id, o);}
377     }
378
379   public void
380     unsubscribe(String JavaDoc id)
381     {
382       _log.trace("unsubscribing: "+id);
383       synchronized (_subscribers) {_subscribers.remove(id);}
384     }
385 }
386
Popular Tags