/*
* 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 org.jboss.classpool.spi;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import javassist.ClassPool;
import org.jboss.classpool.scoped.ScopedClassPool;
import org.jboss.classpool.scoped.ScopedClassPoolFactory;
import org.jboss.classpool.scoped.ScopedClassPoolRepositoryImpl;
/**
* Singleton classpool repository.
*
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
* @author <a href="flavia.rainone@jboss.com">Flavia Rainone</a>
* @version $Revision: 104194 $
*/
public class ClassPoolRepository extends ScopedClassPoolRepositoryImpl
{
private final static ClassPoolRepository instance = new ClassPoolRepository();
private volatile List<ClassPoolRepositoryCallback> callbacks;
private ClassLoaderRegistryHandler registryHandler;
/**
* Returns the singleton instance.
*
* @return the singleton repository instance
*/
public static ClassPoolRepository getInstance()
{
return instance;
}
/**
* Constructor.
*/
protected ClassPoolRepository()
{
super(AbstractClassPoolFactory.getSystemClassPool());
registryHandler = new DefaultClassLoaderRegistryHandler();
super.setClassPoolFactory(new AbstractClassPoolFactory());
}
/**
* Defines the ClassPoolFactory that will be used by this repository.
* @param factory the ClassPoolFactory that is responsible for creating ClassPools for this repository.
* if this factory implements {@link ClassLoaderRegistryHandlerFactory} interface,
* it will also be responsible for creating a ClassLoaderRegistryHandler for this
* repository
*/
@Override
public void setClassPoolFactory(ScopedClassPoolFactory factory)
{
if (factory instanceof ClassLoaderRegistryHandlerFactory)
{
ClassLoaderRegistryHandlerFactory registryHandlerFactory = (ClassLoaderRegistryHandlerFactory) factory;
registryHandler = registryHandlerFactory.create(new DefaultClassLoaderRegistryHandler());
}
super.setClassPoolFactory(factory);
}
/**
* Adds a callback object for notifications on classloader registration.
*
* @param callback the callback object
* @see ClassPoolRepositoryCallback
* @throws IllegalArgumentException if the passed in callback was null
*/
public void addClassPoolRepositoryCallback(ClassPoolRepositoryCallback callback)
{
if (callback == null)
throw new IllegalArgumentException("Null callback");
if (callbacks == null)
{
synchronized(this)
{
if (callbacks == null)
{
callbacks = new CopyOnWriteArrayList<ClassPoolRepositoryCallback>();
}
}
}
callbacks.add(callback);
}
/**
* Returns the callback objects.
* @return the callback objects in an unmodifiable list. If there are none an empty list is returned
*/
public List<ClassPoolRepositoryCallback> getClassPoolRepositoryCallbacks()
{
List<ClassPoolRepositoryCallback> cbs = callbacks;
if (cbs == null || cbs.size() == 0)
return Collections.<ClassPoolRepositoryCallback>emptyList();
return Collections.unmodifiableList(callbacks);
}
/**
* Removes a callback object. If the callback object is null, or it cannot be found in the list, no error is thrown.
* @param callback the callback object
*/
public boolean removeClassPoolRepositoryCallback(ClassPoolRepositoryCallback callback)
{
if (callback == null)
return false;
if (callbacks == null)
return false;
return callbacks.remove(callback);
}
/**
* Registers {@code classLoader} and returns the corresponding {@code ClassPool}.
*
* @param classLoader the ClassLoader to be added to this repository
* @return the ClassPool corresponding to {@code classLoader}
*/
public ClassPool registerClassLoader(ClassLoader classLoader)
{
ClassPool classPool = registryHandler.registerClassLoader(classLoader);
// TODO review classPool != null check for AOP tests
if (callbacks != null && callbacks.size() > 0)
{
for (ClassPoolRepositoryCallback callback : callbacks)
{
callback.classLoaderRegistered(classLoader);
}
}
return classPool;
}
/**
* Unregisters {@code classLoader}.
*
* @param classLoader the ClassLoader to be removed from this repository
*/
public void unregisterClassLoader(ClassLoader classLoader)
{
registryHandler.unregisterClassLoader(classLoader);
if (callbacks != null && callbacks.size() > 0)
{
for (ClassPoolRepositoryCallback callback : callbacks)
{
callback.classLoaderUnregistered(classLoader);
}
}
}
private class DefaultClassLoaderRegistryHandler implements ClassLoaderRegistryHandler
{
private final ConcurrentMap<ClassLoader, Boolean> currentClassLoaders = new ConcurrentHashMap<ClassLoader, Boolean>();
public ClassPool registerClassLoader(ClassLoader classLoader)
{
if (classLoader == null)
{
classLoader = SecurityActions.getContextClassLoader();
}
if (currentClassLoaders.putIfAbsent(classLoader, Boolean.TRUE) != null)
{
return null;
}
ScopedClassPool classPool = (ScopedClassPool) ClassPoolRepository.super.registerClassLoader(classLoader);
currentClassLoaders.remove(classLoader);
return classPool;
}
public void unregisterClassLoader(ClassLoader classLoader)
{
ClassPoolRepository.super.unregisterClassLoader(classLoader);
}
public void setSuccessor(ClassLoaderRegistryHandler handler)
{
throw new IllegalStateException("Default ClassLoaderRegistryHandler cannot have a sucessor");
}
}
}