introduced the use of the Jakarta Commons Collections - revamped ObjectCache

to include an LRU hard reference map and simplified it greatly in the process
This commit is contained in:
Eric J. Bowersox 2002-05-27 08:13:39 +00:00
parent 86d9a90f54
commit dc28dfeb3e
5 changed files with 51 additions and 82 deletions

1
lib/.gitignore vendored
View File

@ -1,4 +1,5 @@
bsf.jar
commons-collections.jar
jacl.jar
jakarta-regexp*.jar
js.jar

View File

@ -6,6 +6,8 @@ compatible with the versions specified here.
Library Version File Name(s) Install To
-------------------------------------------------------------------------------------------------
Apache Jakarta Commons 2.0 commons-collections.jar Venice "lib" subdirectory
Collections
Apache Jakarta Regexp 1.2 jakarta-regexp-1.2.jar Venice "lib" subdirectory
Apache LOG4J 1.1.3 log4j.jar Venice "lib" subdirectory
Bean Scripting Framework 2.2 bsf.jar Venice "lib" subdirectory

View File

@ -11,14 +11,13 @@
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
* Copyright (C) 2001-02 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.util.cache;
import java.lang.ref.*;
import java.util.*;
import org.apache.commons.collections.*;
/**
* A chache which stores objects by key value, and is capable of creating them given an instance of
@ -28,7 +27,6 @@ import java.util.*;
* @author Eric J. Bowersox &lt;erbo@silcom.com&gt;
* @version X
* @see ObjectFactory
* @see java.lang.ref.SoftReference
*/
public class ObjectCache
{
@ -37,10 +35,9 @@ public class ObjectCache
*--------------------------------------------------------------------------------
*/
private HashMap the_data = new HashMap(); // the actual underlying map
private ObjectFactory factory; // used to create new objects
private ReferenceQueue rq = new ReferenceQueue(); // where our references go when they die
private ArrayList sweeper = new ArrayList(); // temporary used in doing sweeps
private SoftRefHashMap the_data = new SoftRefHashMap(); // actual main data store
private LRUMap mru_cache; // most-recently-used map
private ObjectFactory factory; // used to create new objects
/*--------------------------------------------------------------------------------
* Constructor
@ -55,57 +52,25 @@ public class ObjectCache
*/
public ObjectCache(ObjectFactory factory)
{
if (factory==null)
throw new NullPointerException("object factory cannot be null!");
this.factory = factory;
this(factory,5);
} // end constructor
/*--------------------------------------------------------------------------------
* Internal operations
*--------------------------------------------------------------------------------
*/
/**
* "Sweeps" the cache by taking all references that have been cleared and queued by the garbage
* collector and removing them from the map. Should be called fairly often, to minimize wasted
* hashmap slots.
* Creates a new <CODE>ObjectCache</CODE>.
*
* @param factory The factory object used to create new objects when <CODE>getOrCreate</CODE> is called.
* @param lru_size How many objects to maintain hard references to.
* @exception java.lang.NullPointerException The object factory passed in is <CODE>null</CODE>.
*/
private synchronized void doSweep()
public ObjectCache(ObjectFactory factory, int lru_size)
{
Set entries = the_data.entrySet(); // used to find entries with the specified value
Reference r = rq.poll(); // reference that's been cleared
Iterator it;
if (factory==null)
throw new NullPointerException("object factory cannot be null!");
this.factory = factory;
this.mru_cache = new LRUMap(lru_size);
while (r!=null)
{ // look for this reference in our hash map
it = entries.iterator();
while (it.hasNext())
{ // look for the map entry containing the reference
Map.Entry ntry = (Map.Entry)(it.next());
if (r==(Reference)(ntry.getValue()))
{ // found the entry with this reference - nuke it
sweeper.add(ntry.getKey());
break; // don't need to take this loop any farther
} // end if
} // end while
r = rq.poll(); // get the next cleared reference
} // end while
if (sweeper.isEmpty())
return; // no entries to remove
// Remove all the corresponding keys from the hashmap.
it = sweeper.iterator();
while (it.hasNext())
the_data.remove(it.next());
sweeper.clear(); // reset for next time
} // end doSweep
} // end constructor
/*--------------------------------------------------------------------------------
* External operations
@ -120,9 +85,17 @@ public class ObjectCache
*/
public synchronized Object get(Object key)
{
doSweep();
SoftReference r = (SoftReference)(the_data.get(key));
return ((r==null) ? null : r.get());
the_data.purge();
Object rc = mru_cache.get(key);
if (rc==null)
{ // retrieve from main map, poke back into cache
rc = the_data.get(key);
if (rc!=null)
mru_cache.put(key,rc);
} // end if
return rc;
} // end get
@ -137,18 +110,14 @@ public class ObjectCache
*/
public synchronized Object getOrCreate(Object key) throws ObjectFactoryException
{
doSweep();
SoftReference r = (SoftReference)(the_data.get(key));
Object rc = ((r==null) ? null : r.get());
Object rc = this.get(key);
if (rc==null)
{ // attempt to create a new object
{ // create a new object
rc = factory.newObject(key);
if (rc!=null)
{ // clear the old reference, throw it away, and put in a new one
if (r!=null)
r.clear();
r = new SoftReference(rc,rq);
the_data.put(key,r);
{ // stash in both main map and cache
the_data.put(key,rc);
mru_cache.put(key,rc);
} // end if
@ -168,13 +137,11 @@ public class ObjectCache
*/
public synchronized void register(Object key, Object data)
{
doSweep();
SoftReference old = (SoftReference)(the_data.get(key));
if ((old!=null) && (old.get()!=null))
the_data.purge();
if (the_data.get(key)!=null)
throw new ObjectCacheException("object already in cache",key);
the_data.put(key,new SoftReference(data,rq));
if (old!=null)
old.clear();
the_data.put(key,data);
mru_cache.put(key,data);
} // end register
@ -185,11 +152,18 @@ public class ObjectCache
*/
public synchronized void detach(Object key)
{
doSweep();
SoftReference old = (SoftReference)(the_data.remove(key));
if (old!=null)
old.clear();
mru_cache.remove(key);
the_data.remove(key);
the_data.purge();
} // end detach
public synchronized void shutdown()
{
mru_cache.clear();
the_data.clear();
the_data.purge();
} // end shutdown
} // end class ObjectCache

View File

@ -158,8 +158,6 @@ class CommunityUserContextImpl implements CommunityContext, CommunityBackend
if (deleted)
throw new DataException("This community has been deleted.");
data = env.getEngine().getCommunityDataObject(cid);
if (data!=null)
env.getUser().saveMRU("community",data);
// clear cache when we get the real data
cache = null;
@ -179,8 +177,6 @@ class CommunityUserContextImpl implements CommunityContext, CommunityBackend
try
{ // attempt to load the CommunityDataObject
data = env.getEngine().getCommunityDataObject(cid);
if (data!=null)
env.getUser().saveMRU("community",data);
} // end try
catch (DataException e)

View File

@ -219,8 +219,6 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend
if (deleted)
throw new DataException("This conference has been deleted.");
confdata = env.getCommunity().getConferenceDataObject(confid);
if (confdata!=null)
env.getUser().saveMRU("conf",confdata);
// clear cache when we get the real confdata
cache = null;
@ -241,8 +239,6 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend
try
{ // attempt to load the ConferenceCommunityContext
confdata = env.getCommunity().getConferenceDataObject(confid);
if (confdata!=null)
env.getUser().saveMRU("conf",confdata);
} // end try
catch (DataException e)