Browse Source

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
tags/rel_3_17_1_ga
kkhan 18 years ago
parent
commit
a241e04409

+ 1
- 1
src/main/META-INF/MANIFEST.MF View File

@@ -2,7 +2,7 @@ Manifest-Version: 1.1
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/

+ 279
- 0
src/main/javassist/scopedpool/ScopedClassPool.java View File

@@ -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());
}
}

+ 36
- 0
src/main/javassist/scopedpool/ScopedClassPoolFactory.java View File

@@ -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);
}

+ 43
- 0
src/main/javassist/scopedpool/ScopedClassPoolFactoryImpl.java View File

@@ -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);
}
}

+ 94
- 0
src/main/javassist/scopedpool/ScopedClassPoolRepository.java View File

@@ -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);
}

+ 212
- 0
src/main/javassist/scopedpool/ScopedClassPoolRepositoryImpl.java View File

@@ -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;
}
}

+ 247
- 0
src/main/javassist/scopedpool/SoftValueHashMap.java View File

@@ -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();
}
}

Loading…
Cancel
Save