KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > barracuda > plankton > data > ObjectRepository


1 /*
2  * Copyright (C) 2003 Christian Cryder [christianc@granitepeaks.com]
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * $Id: ObjectRepository.java,v 1.13 2004/02/01 05:16:28 christianc Exp $
19  */

20 package org.enhydra.barracuda.plankton.data;
21
22 import java.io.*;
23 import java.lang.ref.*;
24 import java.util.*;
25 import javax.servlet.*;
26 import javax.servlet.http.*;
27
28 import org.apache.log4j.*;
29
30 /**
31  * This class provides access to several different generic statemap repositories,
32  * scoped for Global, Session, Local, or custom (NameSpace or Name...you provide
33  * the cleanup). The basic idea here is to make it easy to access object repositories
34  * without having to pass references around.
35  *
36  * The Global object repository represents a common (threadsafe) statemap that is
37  * shared across the JVM. You would typically put things here like DataSources, global
38  * variables, etc. Any objects that you make available globally need to be threadsafe.
39  *
40  * The Session object repository is a statemap wrapper around HttpSession. This provides
41  * a convenient bridge to the Session interface, without having to have a reference to
42  * the HttpServletRequest. Storing items in this object places them in the underlying session.
43  * Note that ApplicationGateway and ComponentGateway classes invoke the setupSessionRepository()
44  * call for you, so all you have to do is call getSessionRepository() and you're in business.
45  *
46  * The Local object repository is a statemap object that lasts for the duration of a req-resp
47  * cycle. Note that the ApplicationGateway and ComponentGateway classes clean up both Session and
48  * Local repositories.
49  *
50  * The Weak and Soft maps are backed by WeakHashMap and SoftHashMap maps respectively (the basic
51  * distinction being that weak references will generally be cleaned up as soon as possible while
52  * soft references will generally be held on to as long as possible). The soft map is generally
53  * a better choice for caching.
54  *
55  * You can also get non-scoped ObjectRepositories by using either NameSpace or String keys. IF you
56  * use this approach, its up to you to manually remove the repositories when you're done with them
57  * (or else you'll end up leaving them in memory taking up space).
58  *
59  * @author Christian Cryder
60  * @version 1.0
61  */

62 public class ObjectRepository extends DefaultStateMap {
63
64     //public constants
65
private static final Class JavaDoc CLASS = ObjectRepository.class;
66     private static final Logger logger = Logger.getLogger(CLASS);
67
68 // public static final String HTTP_SESSION = ObjectRepository.class.getName()+".HttpSession";
69

70     protected static ObjectRepository global = new ThreadsafeRepository("GlobalOR");
71     protected static ObjectRepository weakGlobal = new WeakThreadsafeRepository("WeakGlobalOR"); //csc_082302.2 - added
72
protected static ObjectRepository softGlobal = new SoftThreadsafeRepository("SoftGlobalOR"); //csc_052702.1 - added
73
protected static SoftHashMap rawSessions = new SoftHashMap(); //csc_011604_1
74
protected static Map session = new HashMap();
75     protected static Map sessionIDs = new HashMap(); //csc_011704_1
76
protected static Map weaksession = new HashMap();
77     protected static Map softsession = new HashMap(); //csc_052702.1 - added
78
protected static Map local = new HashMap();
79     protected static Map custom = new HashMap();
80
81     protected String JavaDoc name = "[unnamed]";
82
83
84     /**
85      * protected constructor
86      */

87     protected ObjectRepository() {
88         this(null);
89     }
90     protected ObjectRepository(String JavaDoc iname) {
91         if (iname!=null) name = iname;
92     }
93     
94     /**
95      * Get a reference to the Global repository. This repository
96      * is shared across the entire JVM (consequently its threadsafe).
97      * The global repository never really goes away, so you don't need
98      * to do any cleanup on this one.
99      */

100     public static ObjectRepository getGlobalRepository() {
101         return global;
102     }
103
104     //csc_082302.2 - added
105
/**
106      * Get a reference to the Weak Global repository. This repository
107      * is shared across the entire JVM (consequently its threadsafe),
108      * but like the Weak Session repository, its backed by a weak hash
109      * map, allowing object which are placed in here to be gc'd as needed.
110      */

111     public static ObjectRepository getWeakGlobalRepository() {
112         return weakGlobal;
113     }
114
115     //csc_082302.2 - added
116
/**
117      * Get a reference to the Soft Global repository. This repository
118      * is shared across the entire JVM (consequently its threadsafe),
119      * but like the Soft Session repository, its backed by a soft hash
120      * map, allowing object which are placed in here to be gc'd as needed,
121      * but only when really needed.
122      */

123     public static ObjectRepository getSoftGlobalRepository() {
124         return softGlobal;
125     }
126
127     /**
128      * Set up the Session repository for this particular thread. You must invoke this
129      * method before actually getting the session repository, IFF you actually
130      * want the repository to wrapp the Servlet's Session structure. Otherwise,
131      * when you get the Session repository (below) it will simply return a regular
132      * state map.
133      */

134     public static void setupSessionRepository(HttpServletRequest req) {
135         String JavaDoc key = "SessionOR_"+Thread.currentThread().getName();
136         if (logger.isInfoEnabled()) logger.info("Setting up session repository: "+key);
137         synchronized (session) {
138             session.put(key, new SessionRepository(req));
139         }
140     }
141
142     /**
143      * Get a reference to the Session repository. If you are using this
144      * within Barracuda (ie. ApplicationGateway or ComponentGateway), this
145      * will return a StateMap that wraps the Servlet session.
146      */

147     public static ObjectRepository getSessionRepository() {
148         String JavaDoc key = "SessionOR_"+Thread.currentThread().getName();
149         return getSessionRepository(key);
150     }
151     protected static ObjectRepository getSessionRepository(String JavaDoc key) {
152         if (logger.isInfoEnabled()) logger.info("Getting session repository: "+key);
153         ObjectRepository or = (ObjectRepository) session.get(key);
154         if (or==null) {
155             if (logger.isInfoEnabled()) logger.info("Setting up default session respository: "+key);
156             or = new ObjectRepository(key);
157             synchronized (session) {
158                 session.put(key, or);
159             }
160         }
161         return or;
162     }
163
164     /**
165      * Release the Session repository
166      */

167     public static void removeSessionRepository() {
168         String JavaDoc key = "SessionOR_"+Thread.currentThread().getName();
169         synchronized (session) {
170             //remove the session repository the master session OR
171
SessionRepository sr = (SessionRepository) session.remove(key);
172             HttpServletRequest hsr = (sr!=null ? sr.req : null);
173             HttpSession hs = (hsr!=null ? hsr.getSession(false) : null);
174             
175             //now, if the underlying session exists, we save a reference to it since
176
//it may have been created this pass
177
if (hs!=null) {
178                 try {
179                     hs.getAttributeNames(); //this will test to make sure its not invalidated
180
synchronized(rawSessions) {
181                         rawSessions.put(hs.getId(), hs);
182                     }
183                 } catch (IllegalStateException JavaDoc e) {
184                     //not a big deal - just means that the session was invalidated (perhaps programatically) during
185
//the req cycle, and therefor there is no point in trying to store a reference to this in rawSessions
186
}
187                 synchronized(session) {
188                     sessionIDs.remove(hs.getId());
189                 }
190             }
191             
192             //regardless of the state of the session, we want to completely clean up the
193
//statemap that we were using to wrap it and remove it from the session OR
194
//we do this because next time around, it'll be registered under a different
195
//thread name anyway)
196
if (sr!=null) {
197                 sr.req = null;
198                 sr.map = null;
199             }
200         }
201         if (logger.isInfoEnabled()) logger.info("Removed session repository: "+key);
202     }
203
204     //csc_030602.1 - added
205
/**
206      * Get a reference to a Weak Session repository. Objects placed in here
207      * are scoped to Session, but may be reclaimed by garbage collecter as needed
208      * (so you must always check for null and reinitialize if necessary)
209      */

210     public static ObjectRepository getWeakSessionRepository() {
211         String JavaDoc key = "WeakSessionOR_$$";
212         if (logger.isInfoEnabled()) logger.info("Getting weak session repository: "+key);
213         ObjectRepository session_or = getSessionRepository();
214         ObjectRepository weak_or = (ObjectRepository) session_or.getState(key);
215         if (weak_or==null) {
216             if (logger.isInfoEnabled()) logger.info("Setting up weak session respository: "+key);
217             weak_or = new WeakRepository(key);
218             synchronized (session_or) {
219                 session_or.putState(key, weak_or);
220             }
221         }
222         return weak_or;
223     }
224
225     //csc_052703.1 - added
226
/**
227      * Get a reference to a Soft Session repository. Objects placed in here
228      * are scoped to Session, but may be reclaimed by garbage collecter as needed
229      * (so you must always check for null and reinitialize if necessary)
230      */

231     public static ObjectRepository getSoftSessionRepository() {
232         String JavaDoc key = "SoftSessionOR_$$";
233         if (logger.isInfoEnabled()) logger.info("Getting soft session repository: "+key);
234         ObjectRepository session_or = getSessionRepository();
235         ObjectRepository soft_or = (ObjectRepository) session_or.getState(key);
236         if (soft_or==null) {
237             if (logger.isInfoEnabled()) logger.info("Setting up soft session respository: "+key);
238             soft_or = new SoftRepository(key);
239             synchronized (session_or) {
240                 session_or.putState(key, soft_or);
241             }
242         }
243         return soft_or;
244     }
245
246     /**
247      * Get a reference to the Local repository. This repository is shared
248      * across the thread. If you use this repository, it is your responsibility
249      * to clean things up (unless something else is cleaning it up for you,
250      * like the Barracuda ApplicationGateway or ComponentGateway)
251      */

252     public static ObjectRepository getLocalRepository() {
253         String JavaDoc key = "LocalOR_"+Thread.currentThread().getName();
254         if (logger.isInfoEnabled()) logger.info("Getting local repository: "+key);
255         ObjectRepository or = (ObjectRepository) local.get(key);
256         if (or==null) {
257             if (logger.isInfoEnabled()) logger.info("Creating new local repository: "+key);
258             or = new ObjectRepository(key);
259             local.put(key, or);
260         }
261         return or;
262     }
263
264     /**
265      * Release the Local repository.
266      */

267     public static void removeLocalRepository() {
268         String JavaDoc key = "LocalOR_"+Thread.currentThread().getName();
269         local.remove(key);
270         if (logger.isInfoEnabled()) logger.info("Removed local repository: "+key);
271     }
272
273     /**
274      * Get an object repository associated with a given NameSpace. If
275      * the object repository for this namespace does not already exist,
276      * it will be created automatically.
277      */

278     public static ObjectRepository getObjectRepository(NameSpace ns) {
279         if (logger.isInfoEnabled()) logger.info("Getting custom repository: "+ns);
280         ObjectRepository or = (ObjectRepository) custom.get(ns);
281         if (or==null) {
282             if (logger.isInfoEnabled()) logger.info("Creating new custom repository: "+ns);
283             or = new ObjectRepository(ns.getName());
284             synchronized (custom) {
285                 custom.put(ns, or);
286             }
287         }
288         return or;
289     }
290     
291     /**
292      * Release an object repository associated with a given NameSpace
293      */

294     public static void removeObjectRepository(NameSpace ns) {
295         synchronized (custom) {
296             custom.remove(ns);
297         }
298         if (logger.isInfoEnabled()) logger.info("Removed custom repository: "+ns);
299     }
300
301     /**
302      * Get an object repository based on a given name. If
303      * the object repository for this namespace does not already exist,
304      * it will be created automatically.
305      */

306     public static ObjectRepository getObjectRepository(String JavaDoc name) {
307         if (logger.isInfoEnabled()) logger.info("Getting custom repository: "+name);
308         ObjectRepository or = (ObjectRepository) custom.get(name);
309         if (or==null) {
310             if (logger.isInfoEnabled()) logger.info("Creating new custom repository: "+name);
311             or = new ObjectRepository(name);
312             synchronized (custom) {
313                 custom.put(name, or);
314             }
315         }
316         return or;
317     }
318     
319     /**
320      * Release an object repository associated with a given name
321      */

322     public static void removeObjectRepository(String JavaDoc name) {
323         synchronized (custom) {
324             custom.remove(name);
325         }
326         if (logger.isInfoEnabled()) logger.info("Removed custom repository: "+name);
327     }
328
329     /**
330      * Return the name of this object repository
331      */

332     public String JavaDoc getName() {
333         return name;
334     }
335
336     //csc_011704_1 - added
337
/**
338      * get raw session - this gives you access to the underlying session object
339      */

340     public static HttpSession getRawSession() {
341         HttpServletRequest req = ((SessionRepository) getSessionRepository()).req;
342         return (req!=null ? req.getSession() : null);
343     }
344
345     /**
346      * allows you to invalidate a session by its unique identifier. You should only need to call
347      * this if you are performing large scale session management (ie. logging out all users, etc)
348      */

349     public static void invalidateSession() {
350         HttpServletRequest req = ((SessionRepository) getSessionRepository()).req;
351         HttpSession hs = (req!=null ? req.getSession(false) : null);
352         if (hs!=null) invalidateSession(hs.getId());
353     }
354
355     /**
356      * allows you to invalidate a session by its unique identifier. You should only need to call
357      * this if you are performing large scale session management (ie. logging out all users, etc)
358      */

359     public static void invalidateSession(String JavaDoc sessionID) {
360         //first, clean up any Barracuda structures that might be pointing to this session
361
synchronized (session) {
362             String JavaDoc key = (String JavaDoc) sessionIDs.remove(sessionID);
363             if (key!=null) {
364                 SessionRepository sr = (SessionRepository) session.remove(key);
365                 if (sr!=null) {
366                     sr.map=null;
367                     sr.registered = false;
368                 }
369             }
370         }
371
372         //now see if we can clean up the real session for this id
373
synchronized (rawSessions) {
374             HttpSession hs = (HttpSession) rawSessions.get(sessionID);
375             if (hs!=null) hs.invalidate();
376             rawSessions.remove(sessionID);
377         }
378     }
379     
380     //csc_011704_1 - added
381
/**
382      * allows you to invalidate all rawSessions. You should only need to call
383      * this if you are performing large scale session management (ie. logging out all users, etc)
384      */

385     public static void invalidateAllSessions() {
386         //first, clean up any Barracuda structures that might be pointing to this session
387
synchronized (session) {
388             session = new HashMap();
389             sessionIDs = new HashMap();
390         }
391
392         //now see if we can clean up the real session for this id
393
synchronized (rawSessions) {
394             Iterator it = rawSessions.values().iterator();
395             while (it.hasNext()) {
396                 HttpSession hs = (HttpSession) it.next();
397                 if (hs!=null) hs.invalidate();
398             }
399             rawSessions = new SoftHashMap();
400         }
401     }
402     
403     //csc_011704_1 - revamped
404
/**
405      * This method gives you direct access to the underlying HttpSession data structures (as many as
406      * are registered by Barracuda apps). Developers should almost never need to interact
407      * with these objects directly - this method is primarily intended for debugging purposes.
408      * Note that the Map returned is actually a copy of the underlying store, with keys
409      * conveniently extracted from their SoftReference wrappers.
410      */

411     public static Map getSessionStore() {
412         //for the session list, we want to pull the underlying session objects out of their soft referents
413
synchronized (rawSessions) {
414             Map smap = new HashMap(rawSessions.size());
415             Iterator it = rawSessions.entrySet().iterator();
416             while (it.hasNext()) {
417                 Map.Entry me = (Map.Entry) it.next();
418                 Object JavaDoc key = me.getKey();
419                 Object JavaDoc val = me.getValue();
420                 if (key==null || val==null) continue;
421                 if (key instanceof SoftReference) key = ((SoftReference) key).get();
422                 if (val instanceof SoftReference) val = ((SoftReference) val).get();
423                 smap.put(key, val);
424             }
425             return smap;
426         }
427     }
428
429     //csc_011704_1 - added
430
/**
431      * This method gives you direct access to the underlying HttpSession data structure. You shouldn't
432      * ever need to use this method unless you really know what you are doing.
433      */

434     public static SoftHashMap getRawSessionStore() {
435         return rawSessions;
436     }
437     
438     //csc_011604_1 - added
439
/**
440      * This method gives you direct access to the underlying data structures in which everything
441      * related the the object repository is kept. Developers should almost never need to interact
442      * with these objects directly - this method is primarily intended for debugging purposes
443      */

444     public static Map getObjectRepositoryStore() {
445         //now build a map of all the structures and return it
446
Map m = new TreeMap();
447         m.put("OR1-global", global);
448         m.put("OR2-weak global", weakGlobal);
449         m.put("OR3-soft global", softGlobal);
450         m.put("OR4-rawSessions", getSessionStore());
451         m.put("OR5-weak session", weaksession);
452         m.put("OR6-soft session", softsession);
453         m.put("OR7-local", local);
454         m.put("OR8-custom", custom);
455
456         return m;
457     }
458
459     public static void printStackTrace() {
460         printStackTrace(null);
461     }
462     public static void printStackTrace(String JavaDoc msg) {
463         printStackTrace(msg, System.out);
464     }
465     public static void printStackTrace(String JavaDoc msg, OutputStream out) {
466         try {
467             out.write(("\n\n\n\n\nObjectRepository StackTrace: "+(msg!=null ? "["+msg+"]" : "")+"\n").getBytes());
468             CollectionsUtil.printStackTrace(getObjectRepositoryStore(), out);
469             out.write("\ndone.\n\n\n\n".getBytes());
470         } catch (IOException e) {
471         }
472     }
473
474    /**
475      * A threadsafe wrapper around ObjectRepository
476      */

477     static class ThreadsafeRepository extends ObjectRepository {
478         public ThreadsafeRepository() {
479             super();
480             props = Collections.synchronizedMap(new HashMap());
481         }
482         
483         public ThreadsafeRepository(String JavaDoc iname) {
484             super(iname);
485             props = Collections.synchronizedMap(new HashMap());
486         }
487     }
488
489     /**
490      * A weak wrapper around ObjectRepository (things that get put in
491      * here can get reclaimed by the garbage collecter as needed, so
492      * you must alwasy check for null as you retrieve objects from this
493      * space)
494      */

495     static class WeakRepository extends ObjectRepository {
496         public WeakRepository() {
497             super();
498             props = new WeakHashMap();
499         }
500         
501         public WeakRepository(String JavaDoc iname) {
502             super(iname);
503             props = new WeakHashMap();
504         }
505     }
506
507     /**
508      * A weak threadsafe wrapper around ObjectRepository
509      */

510     static class WeakThreadsafeRepository extends WeakRepository {
511         public WeakThreadsafeRepository() {
512             super();
513             props = Collections.synchronizedMap(props);
514         }
515         
516         public WeakThreadsafeRepository(String JavaDoc iname) {
517             super(iname);
518             props = Collections.synchronizedMap(props);
519         }
520     }
521
522     /**
523      * A soft wrapper around ObjectRepository (things that get put in
524      * here can get reclaimed by the garbage collecter as needed, so
525      * you must alwasy check for null as you retrieve objects from this
526      * space)
527      */

528     static class SoftRepository extends ObjectRepository {
529         public SoftRepository() {
530             super();
531             props = new SoftHashMap();
532         }
533         
534         public SoftRepository(String JavaDoc iname) {
535             super(iname);
536             props = new SoftHashMap();
537         }
538     }
539
540     /**
541      * A soft threadsafe wrapper around ObjectRepository
542      */

543     static class SoftThreadsafeRepository extends SoftRepository {
544         public SoftThreadsafeRepository() {
545             super();
546             props = Collections.synchronizedMap(props);
547         }
548         
549         public SoftThreadsafeRepository(String JavaDoc iname) {
550             super(iname);
551             props = Collections.synchronizedMap(props);
552         }
553     }
554
555     /**
556      * The basic idea behind this is that we want to wrap the session
557      * as a ObjectRepository object. In order to make this work, it's important
558      * that we don't actually cause the session to be instantiated
559      * unless absolutely necessary
560      */

561     public static class SessionRepository extends ObjectRepository {
562         HttpServletRequest req = null;
563         HttpSessionStateMap map = null;
564         boolean registered = false;
565
566         public SessionRepository() {super();}
567         public SessionRepository(String JavaDoc iname) {super(iname);}
568
569         public SessionRepository(HttpServletRequest ireq) {
570             req = ireq;
571             registerSession();
572         }
573
574         //csc_011704_1 - added
575
protected void registerSession() {
576             if (registered) return;
577             HttpSession hs = req.getSession(false);
578             if (hs!=null) {
579                 try {
580                     hs.getCreationTime();
581                     String JavaDoc key = "SessionOR_"+Thread.currentThread().getName();
582                     synchronized(rawSessions) {
583                         if (!rawSessions.containsKey(hs.getId())) rawSessions.put(hs.getId(), hs);
584                     }
585                     synchronized(session) {
586                         if (!sessionIDs.containsKey(hs.getId())) sessionIDs.put(hs.getId(), key);
587                         registered = true;
588                     }
589                 } catch (IllegalStateException JavaDoc e) {
590                     //ok - just means the session has been invalidated
591
}
592             }
593         }
594         
595         public synchronized void putState(Object JavaDoc key, Object JavaDoc val) {
596             if (map==null) {
597                 HttpSession hs = req.getSession();
598                 map = new HttpSessionStateMap(hs);
599 // map.putState(HTTP_SESSION, hs); //csc_111703_1
600
registerSession();
601             }
602             map.putState(key, val);
603         }
604         public synchronized Object JavaDoc getState(Object JavaDoc key) {
605             if (map==null) {
606                 HttpSession hs = req.getSession(false);
607                 if (hs==null) return null;
608                 else map = new HttpSessionStateMap(hs);
609             }
610             return map.getState(key);
611         }
612         public synchronized Object JavaDoc removeState(Object JavaDoc key) {
613             if (map==null) {
614                 HttpSession hs = req.getSession(false);
615                 if (hs==null) return null;
616                 else map = new HttpSessionStateMap(hs);
617             }
618             return map.removeState(key);
619         }
620         public synchronized List getStateKeys() {
621             if (map==null) {
622                 HttpSession hs = req.getSession(false);
623                 if (hs==null) return new ArrayList();
624                 else map = new HttpSessionStateMap(hs);
625             }
626             return map.getStateKeys();
627         }
628         public synchronized Map getStateValues() {
629             if (map==null) {
630                 HttpSession hs = req.getSession(false);
631                 if (hs==null) return new HashMap();
632                 else map = new HttpSessionStateMap(hs);
633             }
634             return map.getStateValues();
635         }
636         //saw_092603_1 begin
637
// The SessionRepository is a little more involved than the others so at this point I left
638
// it the same and just added the method it was missing below.
639
public synchronized void clearState() {
640             if (map==null) {
641                 HttpSession hs = req.getSession(false);
642                 if (hs==null) return;
643                 else map = new HttpSessionStateMap(hs);
644             }
645             map.clearState();
646         }
647         //saw_092603_1 end
648

649         //csc_111703_1 - added
650
public HttpSession getSession() {
651 // return map.getSession();
652
HttpSession hs = req.getSession();
653              registerSession();
654              return hs;
655         }
656     }
657 }
Popular Tags