Specification-Title: Javassist
Created-By: Shigeru Chiba, Tokyo Institute of Technology
Specification-Vendor: Shigeru Chiba, Tokyo Institute of Technology
-Specification-Version: 3.2
+Specification-Version: 3.3.0.snapshot
Main-Class: javassist.CtClass
Name: javassist/
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+* 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);
+}
--- /dev/null
+/*
+* 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);
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+* 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;
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}