diff options
author | kkhan <kkhan@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2006-07-13 09:43:16 +0000 |
---|---|---|
committer | kkhan <kkhan@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2006-07-13 09:43:16 +0000 |
commit | a241e04409c2f15a77f53f5d009d8fd0d3c1923c (patch) | |
tree | 59eb75bfbd52a13922eb37d064d85b10be225da2 /src/main/javassist/scopedpool | |
parent | 5cc7284f993d5156b9b0d7f7be386a485ad053ab (diff) | |
download | javassist-a241e04409c2f15a77f53f5d009d8fd0d3c1923c.tar.gz javassist-a241e04409c2f15a77f53f5d009d8fd0d3c1923c.zip |
Move scoped classpool repository from jboss retro into javassist to have a common place for users like aop and jboss retro
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@289 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
Diffstat (limited to 'src/main/javassist/scopedpool')
6 files changed, 911 insertions, 0 deletions
diff --git a/src/main/javassist/scopedpool/ScopedClassPool.java b/src/main/javassist/scopedpool/ScopedClassPool.java new file mode 100644 index 00000000..07c0c17c --- /dev/null +++ b/src/main/javassist/scopedpool/ScopedClassPool.java @@ -0,0 +1,279 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2005, JBoss Inc., and individual contributors as indicated + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package javassist.scopedpool; + +import java.lang.ref.WeakReference; +import java.util.Iterator; +import java.util.Map; +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.LoaderClassPath; +import javassist.NotFoundException; + +/** + * A scoped class pool + * + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + * @author <a href="adrian@jboss.com">Adrian Brock</a> + * @author <a href="kabir.khan@jboss.com">Kabir Khan</a> + * @version $Revision: 1.1 $ + */ +public class ScopedClassPool extends ClassPool +{ + protected ScopedClassPoolRepository repository; + protected WeakReference classLoader; + protected LoaderClassPath classPath; + protected SoftValueHashMap softcache = new SoftValueHashMap(); + + static + { + ClassPool.doPruning = false; + ClassPool.releaseUnmodifiedClassFile = false; + } + + /** + * Create a new ScopedClassPool. + * + * @param cl the classloader + * @param src the original class pool + * @param repository the repository + */ + protected ScopedClassPool(ClassLoader cl, ClassPool src, ScopedClassPoolRepository repository) + { + super(src); + this.repository = repository; + this.classLoader = new WeakReference(cl); + if (cl != null) + { + classPath = new LoaderClassPath(cl); + this.insertClassPath(classPath); + } + childFirstLookup = true; + } + + /** + * Get the class loader + * + * @return the class loader + */ + public ClassLoader getClassLoader() + { + return getClassLoader0(); + } + + private ClassLoader getClassLoader0() + { + ClassLoader cl = (ClassLoader) classLoader.get(); + if (cl == null) + throw new IllegalStateException("ClassLoader has been garbage collected"); + return cl; + } + + /** + * Close the class pool + */ + public void close() + { + this.removeClassPath(classPath); + classPath.close(); + classes.clear(); + softcache.clear(); + } + + /** + * Flush a class + * + * @param classname the class to flush + */ + public synchronized void flushClass(String classname) + { + classes.remove(classname); + softcache.remove(classname); + } + + /** + * Soften a class + * + * @param clazz the class + */ + public synchronized void soften(CtClass clazz) + { + if (repository.isPrune()) clazz.prune(); + classes.remove(clazz.getName()); + softcache.put(clazz.getName(), clazz); + } + + /** + * Whether the classloader is loader + * + * @return false always + */ + public boolean isUnloadedClassLoader() + { + return false; + } + + /** + * Get the cached class + * + * @param classname the class name + * @return the class + */ + protected CtClass getCached(String classname) + { + CtClass clazz = getCachedLocally(classname); + if (clazz == null) + { + boolean isLocal = false; + + ClassLoader dcl = getClassLoader0(); + if (dcl != null) + { + final int lastIndex = classname.lastIndexOf('$'); + String classResourceName = null; + if (lastIndex < 0) + { + classResourceName = classname.replaceAll("[\\.]", "/") + ".class"; + } + else + { + classResourceName = classname.substring(0, lastIndex).replaceAll("[\\.]", "/") + classname.substring(lastIndex) + ".class"; + } + + isLocal = dcl.getResource(classResourceName) != null; + } + + if (!isLocal) + { + Map registeredCLs = repository.getRegisteredCLs(); + synchronized (registeredCLs) + { + Iterator it = registeredCLs.values().iterator(); + while (it.hasNext()) + { + ScopedClassPool pool = (ScopedClassPool) it.next(); + if (pool.isUnloadedClassLoader()) + { + repository.unregisterClassLoader(pool.getClassLoader()); + continue; + } + + clazz = pool.getCachedLocally(classname); + if (clazz != null) + { + return clazz; + } + } + } + } + } + // *NOTE* NEED TO TEST WHEN SUPERCLASS IS IN ANOTHER UCL!!!!!! + return clazz; + } + + /** + * Cache a class + * + * @param classname the class name + * @param c the ctClass + * @param dynamic whether the class is dynamically generated + */ + protected void cacheCtClass(String classname, CtClass c, boolean dynamic) + { + if (dynamic) + { + super.cacheCtClass(classname, c, dynamic); + } + else + { + if (repository.isPrune()) c.prune(); + softcache.put(classname, c); + } + } + + /** + * Lock a class into the cache + * + * @param c the class + */ + public void lockInCache(CtClass c) + { + super.cacheCtClass(c.getName(), c, false); + } + + /** + * Whether the class is cached in this pooled + * + * @param classname the class name + * @return the cached class + */ + protected CtClass getCachedLocally(String classname) + { + CtClass cached = (CtClass) classes.get(classname); + if (cached != null) return cached; + synchronized (softcache) + { + return (CtClass) softcache.get(classname); + } + } + + /** + * Get any local copy of the class + * + * @param classname the class name + * @return the class + * @throws NotFoundException when the class is not found + */ + public synchronized CtClass getLocally(String classname) throws NotFoundException + { + softcache.remove(classname); + CtClass clazz = (CtClass) classes.get(classname); + if (clazz == null) + { + clazz = createCtClass(classname, true); + if (clazz == null) throw new NotFoundException(classname); + super.cacheCtClass(classname, clazz, false); + } + + return clazz; + } + + /** + * Convert a javassist class to a java class + * + * @param ct the javassist class + * @param loader the loader + * @throws CannotCompileException for any error + */ + public Class toClass(CtClass ct, ClassLoader loader) throws CannotCompileException + { + //We need to pass up the classloader stored in this pool, as the default implementation uses the Thread context cl. + //In the case of JSP's in Tomcat, org.apache.jasper.servlet.JasperLoader will be stored here, while it's parent + //org.jboss.web.tomcat.tc5.WebCtxLoader$ENCLoader is used as the Thread context cl. The invocation class needs to + // be generated in the JasperLoader classloader since in the case of method invocations, the package name will be + //the same as for the class generated from the jsp, i.e. org.apache.jsp. For classes belonging to org.apache.jsp, + //JasperLoader does NOT delegate to its parent if it cannot find them. + lockInCache(ct); + return super.toClass(ct, getClassLoader0()); + } +} diff --git a/src/main/javassist/scopedpool/ScopedClassPoolFactory.java b/src/main/javassist/scopedpool/ScopedClassPoolFactory.java new file mode 100644 index 00000000..a91412e4 --- /dev/null +++ b/src/main/javassist/scopedpool/ScopedClassPoolFactory.java @@ -0,0 +1,36 @@ +/* +* JBoss, Home of Professional Open Source +* Copyright 2005, JBoss Inc., and individual contributors as indicated +* by the @authors tag. See the copyright.txt in the distribution for a +* full listing of individual contributors. +* +* This is free software; you can redistribute it and/or modify it +* under the terms of the GNU Lesser General Public License as +* published by the Free Software Foundation; either version 2.1 of +* the License, or (at your option) any later version. +* +* This software is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this software; if not, write to the Free +* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +* 02110-1301 USA, or see the FSF site: http://www.fsf.org. +*/ +package javassist.scopedpool; + +import javassist.ClassPool; + +/** + * + * @author <a href="kabir.khan@jboss.com">Kabir Khan</a> + * @version $Revision: 1.1 $ + */ +public interface ScopedClassPoolFactory +{ + ScopedClassPool create(ClassLoader cl, ClassPool src, ScopedClassPoolRepository repository); + + ScopedClassPool create(ClassPool src, ScopedClassPoolRepository repository); +} diff --git a/src/main/javassist/scopedpool/ScopedClassPoolFactoryImpl.java b/src/main/javassist/scopedpool/ScopedClassPoolFactoryImpl.java new file mode 100644 index 00000000..d6f26ebd --- /dev/null +++ b/src/main/javassist/scopedpool/ScopedClassPoolFactoryImpl.java @@ -0,0 +1,43 @@ +/* +* JBoss, Home of Professional Open Source +* Copyright 2005, JBoss Inc., and individual contributors as indicated +* by the @authors tag. See the copyright.txt in the distribution for a +* full listing of individual contributors. +* +* This is free software; you can redistribute it and/or modify it +* under the terms of the GNU Lesser General Public License as +* published by the Free Software Foundation; either version 2.1 of +* the License, or (at your option) any later version. +* +* This software is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this software; if not, write to the Free +* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +* 02110-1301 USA, or see the FSF site: http://www.fsf.org. +*/ +package javassist.scopedpool; + +import javassist.ClassPool; + + +/** + * + * @author <a href="kabir.khan@jboss.com">Kabir Khan</a> + * @version $Revision: 1.1 $ + */ +public class ScopedClassPoolFactoryImpl implements ScopedClassPoolFactory +{ + public ScopedClassPool create(ClassLoader cl, ClassPool src, ScopedClassPoolRepository repository) + { + return new ScopedClassPool(cl, src, repository); + } + + public ScopedClassPool create(ClassPool src, ScopedClassPoolRepository repository) + { + return new ScopedClassPool(null, src, repository); + } +} diff --git a/src/main/javassist/scopedpool/ScopedClassPoolRepository.java b/src/main/javassist/scopedpool/ScopedClassPoolRepository.java new file mode 100644 index 00000000..b4d55c0d --- /dev/null +++ b/src/main/javassist/scopedpool/ScopedClassPoolRepository.java @@ -0,0 +1,94 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2005, JBoss Inc., and individual contributors as indicated + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package javassist.scopedpool; + +import java.util.Map; + +import javassist.ClassPool; + +/** + * + * @author <a href="kabir.khan@jboss.com">Kabir Khan</a> + * @version $Revision: 1.1 $ + */ +public interface ScopedClassPoolRepository +{ + void setClassPoolFactory(ScopedClassPoolFactory factory); + + ScopedClassPoolFactory getClassPoolFactory(); + + /** + * Get the prune. + * + * @return the prune. + */ + boolean isPrune(); + + /** + * Set the prune. + * + * @param prune the prune. + */ + void setPrune(boolean prune); + + /** + * Create a scoped classpool + * + * @param cl the classloader + * @param src the original classpool + * @return the classpool + */ + ScopedClassPool createScopedClassPool(ClassLoader cl, ClassPool src); + + /** + * Finds a scoped classpool registered under the passed in classloader + * @param the classloader + * @return the classpool + */ + ClassPool findClassPool(ClassLoader cl); + + /** + * Register a classloader + * + * @param ucl the classloader + * @return the classpool + */ + ClassPool registerClassLoader(ClassLoader ucl); + + /** + * Get the registered classloaders + * + * @return the registered classloaders + */ + Map getRegisteredCLs(); + + /** + * This method will check to see if a register classloader has been undeployed (as in JBoss) + */ + void clearUnregisteredClassLoaders(); + + /** + * Unregisters a classpool and unregisters its classloader. + * @ClassLoader the classloader the pool is stored under + */ + void unregisterClassLoader(ClassLoader cl); +}
\ No newline at end of file diff --git a/src/main/javassist/scopedpool/ScopedClassPoolRepositoryImpl.java b/src/main/javassist/scopedpool/ScopedClassPoolRepositoryImpl.java new file mode 100644 index 00000000..6fca47ec --- /dev/null +++ b/src/main/javassist/scopedpool/ScopedClassPoolRepositoryImpl.java @@ -0,0 +1,212 @@ +/* +* JBoss, Home of Professional Open Source +* Copyright 2005, JBoss Inc., and individual contributors as indicated +* by the @authors tag. See the copyright.txt in the distribution for a +* full listing of individual contributors. +* +* This is free software; you can redistribute it and/or modify it +* under the terms of the GNU Lesser General Public License as +* published by the Free Software Foundation; either version 2.1 of +* the License, or (at your option) any later version. +* +* This software is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this software; if not, write to the Free +* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +* 02110-1301 USA, or see the FSF site: http://www.fsf.org. +*/ +package javassist.scopedpool; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.WeakHashMap; + +import javassist.ClassPool; +import javassist.LoaderClassPath; + +/** + * + * @author <a href="kabir.khan@jboss.com">Kabir Khan</a> + * @version $Revision: 1.1 $ + */ +public class ScopedClassPoolRepositoryImpl implements ScopedClassPoolRepository +{ + /** The instance */ + private static final ScopedClassPoolRepositoryImpl instance = new ScopedClassPoolRepositoryImpl(); + + /** Whether to prune */ + private boolean prune = true; + + /** Whether to prune when added to the classpool's cache */ + boolean pruneWhenCached; + + /** The registered classloaders */ + protected Map registeredCLs = Collections.synchronizedMap(new WeakHashMap()); + + /** The default class pool */ + protected ClassPool classpool; + + /** The factory for creating class pools */ + protected ScopedClassPoolFactory factory = new ScopedClassPoolFactoryImpl(); + + /** + * Get the instance + * + * @return the instance + */ + public static ScopedClassPoolRepository getInstance() + { + return instance; + } + + /** + * Singleton + */ + private ScopedClassPoolRepositoryImpl() + { + classpool = ClassPool.getDefault(); + // FIXME This doesn't look correct + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + classpool.insertClassPath(new LoaderClassPath(cl)); + } + + /** + * Get the prune. + * + * @return the prune. + */ + public boolean isPrune() + { + return prune; + } + + /** + * Set the prune. + * + * @param prune the prune. + */ + public void setPrune(boolean prune) + { + this.prune = prune; + } + + /** + * Create a scoped classpool + * + * @param cl the classloader + * @param src the original classpool + * @return the classpool + */ + public ScopedClassPool createScopedClassPool(ClassLoader cl, ClassPool src) + { + return factory.create(cl, src, this); + } + + public ClassPool findClassPool(ClassLoader cl) + { + if (cl == null) + return registerClassLoader(ClassLoader.getSystemClassLoader()); + return registerClassLoader(cl); + } + + /** + * Register a classloader + * + * @param ucl the classloader + * @return the classpool + */ + public ClassPool registerClassLoader(ClassLoader ucl) + { + synchronized (registeredCLs) + { + // FIXME: Probably want to take this method out later + // so that AOP framework can be independent of JMX + // This is in here so that we can remove a UCL from the ClassPool as a + // ClassPool.classpath + if (registeredCLs.containsKey(ucl)) + { + return (ClassPool) registeredCLs.get(ucl); + } + ScopedClassPool pool = createScopedClassPool(ucl, classpool); + registeredCLs.put(ucl, pool); + return pool; + } + } + + /** + * Get the registered classloaders + * + * @return the registered classloaders + */ + public Map getRegisteredCLs() + { + clearUnregisteredClassLoaders(); + return registeredCLs; + } + + /** + * This method will check to see if a register classloader has been undeployed (as in JBoss) + */ + public void clearUnregisteredClassLoaders() + { + ArrayList toUnregister = null; + synchronized (registeredCLs) + { + Iterator it = registeredCLs.values().iterator(); + while (it.hasNext()) + { + ScopedClassPool pool = (ScopedClassPool) it.next(); + if (pool.isUnloadedClassLoader()) + { + it.remove(); + ClassLoader cl = pool.getClassLoader(); + if (cl != null) + { + if (toUnregister == null) + { + toUnregister = new ArrayList(); + } + toUnregister.add(cl); + } + } + } + if (toUnregister != null) + { + for (int i = 0; i < toUnregister.size(); i++) + { + unregisterClassLoader((ClassLoader) toUnregister.get(i)); + } + } + } + } + + public void unregisterClassLoader(ClassLoader cl) + { + synchronized (registeredCLs) + { + ScopedClassPool pool = (ScopedClassPool) registeredCLs.remove(cl); + if (pool != null) pool.close(); + } + } + + public void insertDelegate(ScopedClassPoolRepository delegate) + { + //Noop - this is the end + } + + public void setClassPoolFactory(ScopedClassPoolFactory factory) + { + this.factory = factory; + } + + public ScopedClassPoolFactory getClassPoolFactory() + { + return factory; + } +} diff --git a/src/main/javassist/scopedpool/SoftValueHashMap.java b/src/main/javassist/scopedpool/SoftValueHashMap.java new file mode 100644 index 00000000..b2361600 --- /dev/null +++ b/src/main/javassist/scopedpool/SoftValueHashMap.java @@ -0,0 +1,247 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2005, JBoss Inc., and individual contributors as indicated + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package javassist.scopedpool; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.util.AbstractMap; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + + +/** + * This Map will remove entries when the value in the map has been + * cleaned from garbage collection + * + * @version <tt>$Revision: 1.1 $</tt> + * @author <a href="mailto:bill@jboss.org">Bill Burke</a> + */ +public class SoftValueHashMap + extends AbstractMap + implements Map +{ + private static class SoftValueRef extends SoftReference + { + public Object key; + + private SoftValueRef(Object key, Object val, ReferenceQueue q) + { + super(val, q); + this.key = key; + } + + private static SoftValueRef create(Object key, Object val, ReferenceQueue q) + { + if (val == null) return null; + else return new SoftValueRef(key, val, q); + } + + } + public Set entrySet() + { + processQueue(); + return hash.entrySet(); + } + + /* Hash table mapping WeakKeys to values */ + private Map hash; + + /* Reference queue for cleared WeakKeys */ + private ReferenceQueue queue = new ReferenceQueue(); + + /* Remove all invalidated entries from the map, that is, remove all entries + whose values have been discarded. + */ + private void processQueue() + { + SoftValueRef ref; + while ((ref = (SoftValueRef)queue.poll()) != null) { + if (ref == (SoftValueRef) hash.get(ref.key)) { + // only remove if it is the *exact* same WeakValueRef + // + hash.remove(ref.key); + } + } + } + + + /* -- Constructors -- */ + + /** + * Constructs a new, empty <code>WeakHashMap</code> with the given + * initial capacity and the given load factor. + * + * @param initialCapacity The initial capacity of the + * <code>WeakHashMap</code> + * + * @param loadFactor The load factor of the <code>WeakHashMap</code> + * + * @throws IllegalArgumentException If the initial capacity is less than + * zero, or if the load factor is + * nonpositive + */ + public SoftValueHashMap(int initialCapacity, float loadFactor) + { + hash = new HashMap(initialCapacity, loadFactor); + } + + /** + * Constructs a new, empty <code>WeakHashMap</code> with the given + * initial capacity and the default load factor, which is + * <code>0.75</code>. + * + * @param initialCapacity The initial capacity of the + * <code>WeakHashMap</code> + * + * @throws IllegalArgumentException If the initial capacity is less than + * zero + */ + public SoftValueHashMap(int initialCapacity) + { + hash = new HashMap(initialCapacity); + } + + /** + * Constructs a new, empty <code>WeakHashMap</code> with the default + * initial capacity and the default load factor, which is + * <code>0.75</code>. + */ + public SoftValueHashMap() + { + hash = new HashMap(); + } + + /** + * Constructs a new <code>WeakHashMap</code> with the same mappings as the + * specified <tt>Map</tt>. The <code>WeakHashMap</code> is created with an + * initial capacity of twice the number of mappings in the specified map + * or 11 (whichever is greater), and a default load factor, which is + * <tt>0.75</tt>. + * + * @param t the map whose mappings are to be placed in this map. + * @since 1.3 + */ + public SoftValueHashMap(Map t) + { + this(Math.max(2*t.size(), 11), 0.75f); + putAll(t); + } + + /* -- Simple queries -- */ + + /** + * Returns the number of key-value mappings in this map. + * <strong>Note:</strong> <em>In contrast with most implementations of the + * <code>Map</code> interface, the time required by this operation is + * linear in the size of the map.</em> + */ + public int size() + { + processQueue(); + return hash.size(); + } + + /** + * Returns <code>true</code> if this map contains no key-value mappings. + */ + public boolean isEmpty() + { + processQueue(); + return hash.isEmpty(); + } + + /** + * Returns <code>true</code> if this map contains a mapping for the + * specified key. + * + * @param key The key whose presence in this map is to be tested + */ + public boolean containsKey(Object key) + { + processQueue(); + return hash.containsKey(key); + } + + /* -- Lookup and modification operations -- */ + + /** + * Returns the value to which this map maps the specified <code>key</code>. + * If this map does not contain a value for this key, then return + * <code>null</code>. + * + * @param key The key whose associated value, if any, is to be returned + */ + public Object get(Object key) + { + processQueue(); + SoftReference ref = (SoftReference)hash.get(key); + if (ref != null) return ref.get(); + return null; + } + + /** + * Updates this map so that the given <code>key</code> maps to the given + * <code>value</code>. If the map previously contained a mapping for + * <code>key</code> then that mapping is replaced and the previous value is + * returned. + * + * @param key The key that is to be mapped to the given + * <code>value</code> + * @param value The value to which the given <code>key</code> is to be + * mapped + * + * @return The previous value to which this key was mapped, or + * <code>null</code> if if there was no mapping for the key + */ + public Object put(Object key, Object value) + { + processQueue(); + Object rtn = hash.put(key, SoftValueRef.create(key, value, queue)); + if (rtn != null) rtn = ((SoftReference)rtn).get(); + return rtn; + } + + /** + * Removes the mapping for the given <code>key</code> from this map, if + * present. + * + * @param key The key whose mapping is to be removed + * + * @return The value to which this key was mapped, or <code>null</code> if + * there was no mapping for the key + */ + public Object remove(Object key) + { + processQueue(); + return hash.remove(key); + } + + /** + * Removes all mappings from this map. + */ + public void clear() + { + processQueue(); + hash.clear(); + } +} |