package org.jboss.mx.loading;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.security.PrivilegedAction;
import java.security.AccessController;
import org.jboss.logging.Logger;
import org.jboss.mx.loading.ClassLoadingTask.ThreadTask;
public class LoadMgr3
{
private static Logger log = Logger.getLogger(LoadMgr3.class);
private static Object registrationLock = new Object();
private static HashMap loadClassThreads = new HashMap();
private static Map loadTasksByThread = Collections.synchronizedMap(new WeakHashMap());
private static SecurityManager sm = System.getSecurityManager();
public static class PkgClassLoader
{
public final RepositoryClassLoader ucl;
public final int order;
public PkgClassLoader(RepositoryClassLoader ucl)
{
this(ucl, Integer.MAX_VALUE);
}
public PkgClassLoader(RepositoryClassLoader ucl, int order)
{
this.ucl = ucl;
this.order = order;
}
public String toString()
{
StringBuffer buffer = new StringBuffer(100);
buffer.append(super.toString());
buffer.append("{ucl=").append(ucl);
buffer.append(" order=").append(order);
buffer.append('}');
return buffer.toString();
}
}
private static class ResourceAction implements PrivilegedAction
{
RepositoryClassLoader ucl;
String classRsrcName;
ResourceAction(RepositoryClassLoader ucl, String classRsrcName)
{
this.ucl = ucl;
this.classRsrcName = classRsrcName;
}
public Object run()
{
URL url = ucl.getResourceLocally(classRsrcName);
ucl = null;
classRsrcName = null;
return url;
}
}
public static void registerLoaderThread(RepositoryClassLoader ucl, Thread t)
{
synchronized( registrationLock )
{
Object prevThread = loadClassThreads.put(ucl, t);
if( log.isTraceEnabled() )
log.trace("registerLoaderThread, ucl="+ucl+", t="+t+", prevT="+prevThread);
synchronized( loadTasksByThread )
{
List taskList = (List) loadTasksByThread.get(t);
if( taskList == null )
{
taskList = Collections.synchronizedList(new LinkedList());
loadTasksByThread.put(t, taskList);
if( log.isTraceEnabled() )
log.trace("created new task list");
}
}
registrationLock.notifyAll();
}
}
public static boolean beginLoadTask(ClassLoadingTask task,
UnifiedLoaderRepository3 repository)
throws ClassNotFoundException
{
boolean trace = log.isTraceEnabled();
if( trace )
log.trace("Begin beginLoadTask, task="+task);
Class cls = repository.loadClassFromCache(task.classname);
if( cls != null )
{
task.loadedClass = cls;
task.state = ClassLoadingTask.FINISHED;
if( trace )
log.trace("End beginLoadTask, loadClassFromCache, classname: "+task.classname);
return true;
}
Set pkgSet = repository.getPackageClassLoaders(task.classname);
if( pkgSet == null || pkgSet.size() == 0 )
{
if (task.stopOrder == Integer.MAX_VALUE)
{
try
{
cls = repository.loadClassFromClassLoader(task.classname, false,
task.requestingClassLoader);
}
catch(LinkageError e)
{
if( trace )
log.trace("End beginLoadTask, LinkageError for task: "+task, e);
throw e;
}
if( cls != null )
{
task.loadedClass = cls;
task.state = ClassLoadingTask.FINISHED;
if( trace )
log.trace("End beginLoadTask, loadClassFromClassLoader");
return true;
}
}
if( trace )
log.trace("End beginLoadTask, ClassNotFoundException");
String msg = "No ClassLoaders found for: "+task.classname;
throw new ClassNotFoundException(msg);
}
Iterator iter = pkgSet.iterator();
RepositoryClassLoader theUCL = null;
int order = Integer.MAX_VALUE;
while( iter.hasNext() )
{
Object next = iter.next();
int uclOrder;
RepositoryClassLoader ucl;
if( next instanceof RepositoryClassLoader )
{
ucl = (RepositoryClassLoader) next;
uclOrder = ucl.getAddedOrder();
}
else
{
PkgClassLoader pkgUcl = (PkgClassLoader) next;
ucl = pkgUcl.ucl;
uclOrder = pkgUcl.order;
}
if (task.stopOrder != Integer.MAX_VALUE && task.stopOrder <= uclOrder)
break;
String classRsrcName = task.classname.replace('.', '/') + ".class";
URL url = null;
if( sm != null )
{
ResourceAction action = new ResourceAction(ucl, classRsrcName);
url = (URL) AccessController.doPrivileged(action);
}
else
{
url = ucl.getResourceLocally(classRsrcName);
}
if( url != null && uclOrder < order )
{
if( trace && theUCL != null )
log.trace("Replacing UCL: "+theUCL+" with UCL:"+ucl);
theUCL = ucl;
order = uclOrder;
}
}
if( theUCL == null && task.stopOrder == Integer.MAX_VALUE)
{
try
{
cls = repository.loadClassFromClassLoader(task.classname, false,
task.requestingClassLoader);
}
catch(LinkageError e)
{
if( trace )
log.trace("End beginLoadTask, LinkageError for task: "+task, e);
throw e;
}
if( cls != null )
{
task.loadedClass = cls;
task.state = ClassLoadingTask.FINISHED;
if( trace )
log.trace("End beginLoadTask, loadClassFromClassLoader");
return true;
}
if( trace )
log.trace("End beginLoadTask, ClassNotFoundException");
String msg = "No ClassLoaders found for: "+task.classname;
throw new ClassNotFoundException(msg);
}
if (theUCL == null)
{
if( trace )
log.trace("End beginLoadTask, ClassNotFoundException");
String msg = "No ClassLoaders found for: "+task.classname;
throw new ClassNotFoundException(msg);
}
scheduleTask(task, theUCL, order, false, trace);
task.state = ClassLoadingTask.FOUND_CLASS_LOADER;
if( trace )
log.trace("End beginLoadTask, task="+task);
return false;
}
public static void nextTask(Thread t, ClassLoadingTask task,
UnifiedLoaderRepository3 repository)
throws InterruptedException
{
boolean trace = log.isTraceEnabled();
List taskList = (List) loadTasksByThread.get(t);
synchronized( taskList )
{
while( taskList.size() == 0 && task.threadTaskCount != 0 )
{
if( trace )
log.trace("Begin nextTask(WAIT_ON_EVENT), task="+task);
try
{
task.state = ClassLoadingTask.WAIT_ON_EVENT;
taskList.wait();
}
catch(InterruptedException e)
{
if( trace )
log.trace("nextTask(WAIT_ON_EVENT), interrupted, task="+task, e);
throw e;
}
if( trace )
log.trace("nextTask(WAIT_ON_EVENT), notified, task="+task);
}
if( trace )
log.trace("Continue nextTask("+taskList.size()+"), task="+task);
if( task.threadTaskCount == 0 )
{
task.state = ClassLoadingTask.FINISHED;
log.trace("End nextTask(FINISHED), task="+task);
return;
}
}
ThreadTask threadTask = (ThreadTask) taskList.remove(0);
ClassLoadingTask loadTask = threadTask.getLoadTask();
if( trace )
log.trace("Begin nextTask("+taskList.size()+"), loadTask="+loadTask);
RepositoryClassLoader ucl3 = threadTask.ucl;
try
{
if( threadTask.t == null )
{
if( trace )
log.trace("Rescheduling threadTask="+threadTask);
scheduleTask(loadTask, ucl3, threadTask.order, true, trace);
}
else
{
if( trace )
log.trace("Running threadTask="+threadTask);
threadTask.run();
}
}
catch(Throwable e)
{
if( e instanceof ClassCircularityError )
{
try
{
if( trace )
log.trace("Run failed with exception", e);
scheduleTask(loadTask, ucl3, Integer.MAX_VALUE, true, trace);
}
catch(ClassNotFoundException ex)
{
loadTask.setLoadError(ex);
log.warn("Failed to reschedule task after CCE", ex);
}
if( trace )
log.trace("Post CCE state, loadTask="+loadTask);
}
else
{
loadTask.setLoadError(e);
if( trace )
log.trace("Run failed with exception", e);
}
}
finally
{
if( threadTask.releaseInNextTask == true )
{
if( trace )
log.trace("Releasing loadLock and ownership of UCL: "+threadTask.ucl);
synchronized( registrationLock )
{
loadClassThreads.remove(threadTask.ucl);
}
synchronized( threadTask.ucl )
{
ucl3.release();
ucl3.notifyAll();
}
}
}
if( loadTask.threadTaskCount == 0 )
{
Class loadedClass = threadTask.getLoadedClass();
if( loadedClass != null )
{
ClassLoader loader = loadedClass.getClassLoader();
ClassLoader wrapper = repository.getWrappingClassLoader(loader);
if (wrapper != null)
loader=wrapper;
repository.cacheLoadedClass(threadTask.getClassname(),
loadedClass, loader);
}
List loadTaskThreadTasks = (List) loadTasksByThread.get(loadTask.requestingThread);
synchronized( loadTaskThreadTasks )
{
if( trace )
log.trace("Notifying task of thread completion, loadTask:"+loadTask);
loadTask.state = ClassLoadingTask.FINISHED;
loadTaskThreadTasks.notify();
}
}
if( trace )
log.trace("End nextTask("+taskList.size()+"), loadTask="+loadTask);
}
public static void endLoadTask(ClassLoadingTask task)
{
boolean trace = log.isTraceEnabled();
if( trace )
log.trace("Begin endLoadTask, task="+task);
synchronized( registrationLock )
{
loadClassThreads.remove(task.requestingClassLoader);
registrationLock.notifyAll();
}
List taskList = (List) loadTasksByThread.get(task.requestingThread);
int size = taskList != null ? taskList.size() : 0;
synchronized( taskList )
{
for(int i = 0; i < size; i ++)
{
ThreadTask threadTask = (ThreadTask) taskList.remove(0);
ClassLoadingTask loadTask = threadTask.getLoadTask();
if( trace )
log.trace("Reassigning task: "+threadTask+", to: "+loadTask.requestingThread);
threadTask.t = null;
List toTaskList = (List) loadTasksByThread.get(loadTask.requestingThread);
synchronized( toTaskList )
{
toTaskList.add(0, threadTask);
loadTask.state = ClassLoadingTask.NEXT_EVENT;
toTaskList.notify();
}
}
}
}
static private void scheduleTask(ClassLoadingTask task, RepositoryClassLoader ucl,
int order, boolean reschedule, boolean trace) throws ClassNotFoundException
{
Thread t = null;
boolean releaseInNextTask = false;
ThreadTask subtask = null;
List taskList = null;
synchronized( registrationLock )
{
t = (Thread) loadClassThreads.get(ucl);
if( t == null )
{
while( t == null && ucl.attempt(1) == false )
{
if( trace )
log.trace("Waiting for owner of UCL: "+ucl);
try
{
registrationLock.wait();
}
catch(InterruptedException e)
{
String msg = "Interrupted waiting for registration notify,"
+ " classame: "+task.classname;
throw new ClassNotFoundException(msg);
}
t = (Thread) loadClassThreads.get(ucl);
if( trace )
log.trace("Notified that UCL owner is: "+t);
}
t = (Thread) loadClassThreads.get(ucl);
if( t == null )
{
releaseInNextTask = true;
t = task.requestingThread;
Object prevThread = loadClassThreads.put(ucl, t);
if( trace )
{
log.trace("scheduleTask, taking ownership of ucl="+ucl
+", t="+t+", prevT="+prevThread);
}
}
}
subtask = task.newThreadTask(ucl, t, order, reschedule,
releaseInNextTask);
taskList = (List) loadTasksByThread.get(t);
synchronized( taskList )
{
taskList.add(subtask);
Collections.sort(taskList, ClassLoadingTask.taskComparator);
taskList.notify();
}
}
if( trace )
log.trace("scheduleTask("+taskList.size()+"), created subtask: "+subtask);
}
}