git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@298 30ef5769-5b8d-40dd-aea6-55b5d6557bb3tags/rel_3_17_1_ga
@@ -1,18 +1,18 @@ | |||
/* | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 2006 JBoss Inc., All Rights Reserved. | |||
* | |||
* The contents of this file are subject to the Mozilla Public License Version | |||
* 1.1 (the "License"); you may not use this file except in compliance with | |||
* the License. Alternatively, the contents of this file may be used under | |||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||
* | |||
* Software distributed under the License is distributed on an "AS IS" | |||
basis, | |||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||
* for the specific language governing rights and limitations under the | |||
* License. | |||
*/ | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 2006 JBoss Inc. All Rights Reserved. | |||
* | |||
* The contents of this file are subject to the Mozilla Public License Version | |||
* 1.1 (the "License"); you may not use this file except in compliance with | |||
* the License. Alternatively, the contents of this file may be used under | |||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||
* | |||
* Software distributed under the License is distributed on an "AS IS" basis, | |||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||
* for the specific language governing rights and limitations under the | |||
* License. | |||
*/ | |||
package javassist.scopedpool; | |||
import java.lang.ref.WeakReference; | |||
@@ -25,249 +25,257 @@ import javassist.LoaderClassPath; | |||
import javassist.NotFoundException; | |||
/** | |||
* A scoped class pool | |||
* 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.2 $ | |||
* @version $Revision: 1.3 $ | |||
*/ | |||
public class ScopedClassPool extends ClassPool | |||
{ | |||
protected ScopedClassPoolRepository repository; | |||
protected WeakReference classLoader; | |||
protected LoaderClassPath classPath; | |||
protected SoftValueHashMap softcache = new SoftValueHashMap(); | |||
public class ScopedClassPool extends ClassPool { | |||
protected ScopedClassPoolRepository repository; | |||
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; | |||
} | |||
protected WeakReference classLoader; | |||
/** | |||
* Get the class loader | |||
* | |||
* @return the class loader | |||
*/ | |||
public ClassLoader getClassLoader() | |||
{ | |||
return getClassLoader0(); | |||
} | |||
protected LoaderClassPath classPath; | |||
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(); | |||
} | |||
protected SoftValueHashMap softcache = new SoftValueHashMap(); | |||
/** | |||
* Flush a class | |||
* | |||
* @param classname the class to flush | |||
*/ | |||
public synchronized void flushClass(String classname) | |||
{ | |||
classes.remove(classname); | |||
softcache.remove(classname); | |||
} | |||
static { | |||
ClassPool.doPruning = false; | |||
ClassPool.releaseUnmodifiedClassFile = false; | |||
} | |||
/** | |||
* 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); | |||
} | |||
/** | |||
* 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; | |||
} | |||
/** | |||
* Whether the classloader is loader | |||
* | |||
* @return false always | |||
*/ | |||
public boolean isUnloadedClassLoader() | |||
{ | |||
return false; | |||
} | |||
/** | |||
* Get the class loader | |||
* | |||
* @return the class loader | |||
*/ | |||
public ClassLoader getClassLoader() { | |||
return getClassLoader0(); | |||
} | |||
/** | |||
* 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"; | |||
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; | |||
} | |||
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; | |||
} | |||
} | |||
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); | |||
} | |||
} | |||
// *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); | |||
} | |||
} | |||
/** | |||
* 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); | |||
} | |||
/** | |||
* 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; | |||
} | |||
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()); | |||
} | |||
/** | |||
* 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()); | |||
} | |||
} |
@@ -1,30 +1,38 @@ | |||
/* | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 2006 JBoss Inc., All Rights Reserved. | |||
* | |||
* The contents of this file are subject to the Mozilla Public License Version | |||
* 1.1 (the "License"); you may not use this file except in compliance with | |||
* the License. Alternatively, the contents of this file may be used under | |||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||
* | |||
* Software distributed under the License is distributed on an "AS IS" | |||
basis, | |||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||
* for the specific language governing rights and limitations under the | |||
* License. | |||
*/ | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 2006 JBoss Inc. All Rights Reserved. | |||
* | |||
* The contents of this file are subject to the Mozilla Public License Version | |||
* 1.1 (the "License"); you may not use this file except in compliance with | |||
* the License. Alternatively, the contents of this file may be used under | |||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||
* | |||
* Software distributed under the License is distributed on an "AS IS" basis, | |||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||
* for the specific language governing rights and limitations under the | |||
* License. | |||
*/ | |||
package javassist.scopedpool; | |||
import javassist.ClassPool; | |||
/** | |||
* | |||
* A factory interface. | |||
* | |||
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a> | |||
* @version $Revision: 1.2 $ | |||
* @version $Revision: 1.3 $ | |||
*/ | |||
public interface ScopedClassPoolFactory | |||
{ | |||
ScopedClassPool create(ClassLoader cl, ClassPool src, ScopedClassPoolRepository repository); | |||
ScopedClassPool create(ClassPool src, ScopedClassPoolRepository repository); | |||
public interface ScopedClassPoolFactory { | |||
/** | |||
* Makes an instance. | |||
*/ | |||
ScopedClassPool create(ClassLoader cl, ClassPool src, | |||
ScopedClassPoolRepository repository); | |||
/** | |||
* Makes an instance. | |||
*/ | |||
ScopedClassPool create(ClassPool src, | |||
ScopedClassPoolRepository repository); | |||
} |
@@ -1,37 +1,42 @@ | |||
/* | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 2006 JBoss Inc., All Rights Reserved. | |||
* | |||
* The contents of this file are subject to the Mozilla Public License Version | |||
* 1.1 (the "License"); you may not use this file except in compliance with | |||
* the License. Alternatively, the contents of this file may be used under | |||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||
* | |||
* Software distributed under the License is distributed on an "AS IS" | |||
basis, | |||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||
* for the specific language governing rights and limitations under the | |||
* License. | |||
*/ | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 2006 JBoss Inc. All Rights Reserved. | |||
* | |||
* The contents of this file are subject to the Mozilla Public License Version | |||
* 1.1 (the "License"); you may not use this file except in compliance with | |||
* the License. Alternatively, the contents of this file may be used under | |||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||
* | |||
* Software distributed under the License is distributed on an "AS IS" basis, | |||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||
* for the specific language governing rights and limitations under the | |||
* License. | |||
*/ | |||
package javassist.scopedpool; | |||
import javassist.ClassPool; | |||
/** | |||
* | |||
* An implementation of factory. | |||
* | |||
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a> | |||
* @version $Revision: 1.2 $ | |||
* @version $Revision: 1.3 $ | |||
*/ | |||
public class ScopedClassPoolFactoryImpl implements ScopedClassPoolFactory | |||
{ | |||
public ScopedClassPool create(ClassLoader cl, ClassPool src, ScopedClassPoolRepository repository) | |||
{ | |||
return new ScopedClassPool(cl, src, repository); | |||
} | |||
public class ScopedClassPoolFactoryImpl implements ScopedClassPoolFactory { | |||
/** | |||
* Makes an instance. | |||
*/ | |||
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); | |||
} | |||
/** | |||
* Makes an instance. | |||
*/ | |||
public ScopedClassPool create(ClassPool src, | |||
ScopedClassPoolRepository repository) { | |||
return new ScopedClassPool(null, src, repository); | |||
} | |||
} |
@@ -1,18 +1,18 @@ | |||
/* | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 2006 JBoss Inc., All Rights Reserved. | |||
* | |||
* The contents of this file are subject to the Mozilla Public License Version | |||
* 1.1 (the "License"); you may not use this file except in compliance with | |||
* the License. Alternatively, the contents of this file may be used under | |||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||
* | |||
* Software distributed under the License is distributed on an "AS IS" | |||
basis, | |||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||
* for the specific language governing rights and limitations under the | |||
* License. | |||
*/ | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 2006 JBoss Inc. All Rights Reserved. | |||
* | |||
* The contents of this file are subject to the Mozilla Public License Version | |||
* 1.1 (the "License"); you may not use this file except in compliance with | |||
* the License. Alternatively, the contents of this file may be used under | |||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||
* | |||
* Software distributed under the License is distributed on an "AS IS" basis, | |||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||
* for the specific language governing rights and limitations under the | |||
* License. | |||
*/ | |||
package javassist.scopedpool; | |||
import java.util.Map; | |||
@@ -20,69 +20,78 @@ import java.util.Map; | |||
import javassist.ClassPool; | |||
/** | |||
* | |||
* An interface to <code>ScopedClassPoolRepositoryImpl</code>. | |||
* | |||
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a> | |||
* @version $Revision: 1.2 $ | |||
* @version $Revision: 1.3 $ | |||
*/ | |||
public interface ScopedClassPoolRepository | |||
{ | |||
void setClassPoolFactory(ScopedClassPoolFactory factory); | |||
ScopedClassPoolFactory getClassPoolFactory(); | |||
public interface ScopedClassPoolRepository { | |||
/** | |||
* Records a factory. | |||
*/ | |||
void setClassPoolFactory(ScopedClassPoolFactory factory); | |||
/** | |||
* Obtains the recorded factory. | |||
*/ | |||
ScopedClassPoolFactory getClassPoolFactory(); | |||
/** | |||
* Returns whether or not the class pool is pruned. | |||
* | |||
* @return the prune. | |||
*/ | |||
boolean isPrune(); | |||
/** | |||
* Get the prune. | |||
* | |||
* @return the prune. | |||
*/ | |||
boolean isPrune(); | |||
/** | |||
* Sets the prune flag. | |||
* | |||
* @param prune a new value. | |||
*/ | |||
void setPrune(boolean prune); | |||
/** | |||
* 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); | |||
/** | |||
* 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); | |||
/** | |||
* Finds a scoped classpool registered under the passed in classloader. | |||
* | |||
* @param cl the classloader. | |||
* @return the classpool. | |||
*/ | |||
ClassPool findClassPool(ClassLoader cl); | |||
/** | |||
* Register a classloader | |||
* | |||
* @param ucl the classloader | |||
* @return the classpool | |||
*/ | |||
ClassPool registerClassLoader(ClassLoader ucl); | |||
/** | |||
* Register a classloader. | |||
* | |||
* @param ucl the classloader. | |||
* @return the classpool. | |||
*/ | |||
ClassPool registerClassLoader(ClassLoader ucl); | |||
/** | |||
* Get the registered classloaders | |||
* | |||
* @return the registered classloaders | |||
*/ | |||
Map getRegisteredCLs(); | |||
/** | |||
* 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(); | |||
/** | |||
* 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); | |||
} | |||
/** | |||
* Unregisters a classpool and unregisters its classloader. | |||
* | |||
* @param cl the classloader the pool is stored under. | |||
*/ | |||
void unregisterClassLoader(ClassLoader cl); | |||
} |
@@ -1,18 +1,18 @@ | |||
/* | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 2006 JBoss Inc., All Rights Reserved. | |||
* | |||
* The contents of this file are subject to the Mozilla Public License Version | |||
* 1.1 (the "License"); you may not use this file except in compliance with | |||
* the License. Alternatively, the contents of this file may be used under | |||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||
* | |||
* Software distributed under the License is distributed on an "AS IS" | |||
basis, | |||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||
* for the specific language governing rights and limitations under the | |||
* License. | |||
*/ | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 2006 JBoss Inc. All Rights Reserved. | |||
* | |||
* The contents of this file are subject to the Mozilla Public License Version | |||
* 1.1 (the "License"); you may not use this file except in compliance with | |||
* the License. Alternatively, the contents of this file may be used under | |||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||
* | |||
* Software distributed under the License is distributed on an "AS IS" basis, | |||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||
* for the specific language governing rights and limitations under the | |||
* License. | |||
*/ | |||
package javassist.scopedpool; | |||
import java.util.ArrayList; | |||
@@ -25,182 +25,163 @@ import javassist.ClassPool; | |||
import javassist.LoaderClassPath; | |||
/** | |||
* | |||
* An implementation of <code>ScopedClassPoolRepository</code>. | |||
* It is an singleton. | |||
* | |||
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a> | |||
* @version $Revision: 1.2 $ | |||
* @version $Revision: 1.3 $ | |||
*/ | |||
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); | |||
} | |||
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)); | |||
} | |||
/** | |||
* Returns the value of the prune attribute. | |||
* | |||
* @return the prune. | |||
*/ | |||
public boolean isPrune() { | |||
return prune; | |||
} | |||
/** | |||
* Set the prune attribute. | |||
* | |||
* @param prune a new value. | |||
*/ | |||
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. | |||
*/ | |||
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)); | |||
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; | |||
} | |||
} | |||
} | |||
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; | |||
} | |||
} |
@@ -1,18 +1,18 @@ | |||
/* | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 2006 JBoss Inc., All Rights Reserved. | |||
* | |||
* The contents of this file are subject to the Mozilla Public License Version | |||
* 1.1 (the "License"); you may not use this file except in compliance with | |||
* the License. Alternatively, the contents of this file may be used under | |||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||
* | |||
* Software distributed under the License is distributed on an "AS IS" | |||
basis, | |||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||
* for the specific language governing rights and limitations under the | |||
* License. | |||
*/ | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 2006 JBoss Inc. All Rights Reserved. | |||
* | |||
* The contents of this file are subject to the Mozilla Public License Version | |||
* 1.1 (the "License"); you may not use this file except in compliance with | |||
* the License. Alternatively, the contents of this file may be used under | |||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||
* | |||
* Software distributed under the License is distributed on an "AS IS" basis, | |||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||
* for the specific language governing rights and limitations under the | |||
* License. | |||
*/ | |||
package javassist.scopedpool; | |||
import java.lang.ref.ReferenceQueue; | |||
@@ -22,220 +22,211 @@ 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.2 $</tt> | |||
* @author <a href="mailto:bill@jboss.org">Bill Burke</a> | |||
* This Map will remove entries when the value in the map has been cleaned from | |||
* garbage collection | |||
* | |||
* @version <tt>$Revision: 1.3 $</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(); | |||
} | |||
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); | |||
} | |||
} | |||
/** | |||
* Returns a set of the mappings contained in this hash table. | |||
*/ | |||
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. | |||
*/ | |||
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(); | |||
} | |||
} |
@@ -0,0 +1,7 @@ | |||
<html> | |||
<body> | |||
<p>A custom class pool for several JBoss products. | |||
It is not part of Javassist. | |||
</p> | |||
</body> | |||
</html> |