in modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/AccumuloVFSClassLoader.java [351:443]
private synchronized void updateDelegateClassloader() throws Exception {
try {
// Re-resolve the files on the classpath, things may have changed.
long retries = 0;
long currentSleepMillis = sleepInterval;
printDebug("Looking for files on classpath: " + this.getClassPath());
FileObject[] classpathFiles = VFSManager.resolve(this.getClassPath());
if (classpathFiles.length == 0) {
while (classpathFiles.length == 0 && retryPermitted(retries)) {
try {
printWarn("VFS path was empty. Waiting " + currentSleepMillis + " ms to retry");
Thread.sleep(currentSleepMillis);
classpathFiles = VFSManager.resolve(this.getClassPath());
retries++;
currentSleepMillis = Math.min(maxWaitInterval, currentSleepMillis + sleepInterval);
} catch (InterruptedException e) {
printError("VFS Retry Interruped");
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
if (classpathFiles.length == 0) {
printError("AccumuloVFSClassLoader has no resources on classpath");
}
this.files = classpathFiles;
// Remove old files from monitor
VFSClassLoaderWrapper currentDelegate = this.cl;
if (null != currentDelegate) {
forEachCatchRTEs(Arrays.stream(currentDelegate.getFileObjects()), f -> {
removeFile(f);
printDebug("removed from monitor: " + f.toString());
});
}
// There is a chance that the listener was removed from the top level directory or
// its children if they were deleted within some time window. Re-add files to be
// monitored. The Monitor will ignore files that are already/still being monitored.
// forEachCatchRTEs will capture a stream of thrown exceptions.
// and can collect them to list or reduce into one exception
forEachCatchRTEs(Arrays.stream(this.files), f -> {
addFileToMonitor(f);
printDebug("now monitoring: " + f.toString());
});
// Create the new classloader delegate
if (DEBUG) {
printDebug("Rebuilding dynamic classloader using files: "
+ Arrays.stream(this.files).map(Object::toString).collect(Collectors.joining(",")));
}
VFSClassLoaderWrapper newDelegate;
if (!this.isPostDelegationModel()) {
// This is the normal classloader parent delegation model
printDebug("Creating new pre-delegating VFSClassLoaderWrapper");
newDelegate = new VFSClassLoaderWrapper(this.files, VFSManager.get(), parent);
} else {
// This delegates to the parent after we lookup locally first.
printDebug("Creating new post-delegating VFSClassLoaderWrapper");
newDelegate = new VFSClassLoaderWrapper(this.files, VFSManager.get(), parent) {
@Override
public synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
// Check to see if this ClassLoader has already loaded the class
Class<?> c = this.findLoadedClass(name);
if (c != null) {
if (DEBUG) {
printDebug("Returning already loaded class: " + name + "@" + c.hashCode()
+ " from classloader: " + c.getClassLoader().hashCode());
}
return c;
}
try {
// try finding this class here instead of parent
Class<?> clazz = super.findClass(name);
if (DEBUG) {
printDebug("Returning newly loaded class: " + name + "@" + clazz.hashCode()
+ " from classloader: " + clazz.getClassLoader().hashCode());
}
return clazz;
} catch (ClassNotFoundException e) {
printDebug("Class " + name + " not found in classloader: " + this.hashCode()
+ ", delegating to parent.");
}
printDebug("Loading class " + name + " from parent classloader");
return super.loadClass(name, resolve);
}
};
}
updateLock.writeLock().lock();
this.cl = newDelegate;
printDebug("AccumuloVFSClassLoader set, hash=" + this.cl.hashCode());
} finally {
updateLock.writeLock().unlock();
}
}