in extensions/jni/nifi-framework-jni/src/main/java/org/apache/nifi/processor/JniClassLoader.java [126:241]
public synchronized void initializeNarDirectory(final String narDirectory,final String narWriteBase,final String docsDir, ClassLoader parent) throws IOException, ClassNotFoundException{
// unpack the nar
if (this.parent != null)
throw new IllegalArgumentException("Already initialized");
this.parent = parent;
List<File> paths = new ArrayList<>();
File narDeploy = new File(narWriteBase);
JniUnpacker.unpackNars(new File(narDirectory),narDeploy,paths);
List<File> directories = Arrays.asList(narDeploy.listFiles(File::isDirectory));
for(File narPath : directories) {
final BundleDetails details = NarBundleUtil.fromNarDirectory(narPath);
bundleMap.put(details.getCoordinate().getId(), details );
fileMap.put(details.getCoordinate().getId(), narPath);
}
// these two allow us to see load those which do not have dependencies followed by those that do
// if a dependency exists within this set then we can chain those class loaders as needed.
final Map<String, Dependency> dependencyMap = new HashMap<>();
final List<String> nonDeps = new ArrayList<>();
bundleMap.entrySet().stream().filter((e) ->{
return e.getValue().getDependencyCoordinate() == null;
}).collect(Collectors.toList()).forEach( entry ->{
File path = fileMap.get(entry.getKey());
if (path != null) {
try {
nonDeps.add(entry.getKey());
final NarClassLoader loader = new NarClassLoader(path, parent);
loaderMap.put(entry.getKey(),loader);
Dependency dep = new Dependency(entry.getKey());
dependencyMap.put(entry.getKey(), dep);
discoverAndLoad(new Bundle(entry.getValue(), loader));
} catch (ClassNotFoundException e) {
logger.error("Could not create NarClassLoader",e);
} catch (IOException e) {
logger.error("Could not create NarClassLoader",e);
}
Dependency dep = new Dependency(entry.getKey());
dependencyMap.put(entry.getKey(), dep);
}
});
bundleMap.entrySet().stream().filter((e) ->{
return e.getValue().getDependencyCoordinate() != null;
}).collect(Collectors.toList()).forEach(entry ->{
File path = fileMap.get(entry.getKey());
if (path != null) {
Dependency dep = dependencyMap.get(entry.getValue().getCoordinate().getId());
if (dep == null) {
dep = new Dependency(entry.getValue().getCoordinate().getId());
dependencyMap.put(entry.getValue().getCoordinate().getId(), dep);
}
Dependency subDep = dependencyMap.get(entry.getValue().getDependencyCoordinate().getId());
if (subDep == null) {
subDep = new Dependency(entry.getValue().getDependencyCoordinate().getId());
dependencyMap.put(entry.getValue().getDependencyCoordinate().getId(), subDep);
}
dep.addDependency(subDep);
}
});
bundleMap.entrySet().stream().filter((e) ->{
return e.getValue().getDependencyCoordinate() != null;
}).collect(Collectors.toList()).forEach(entry ->{
try {
Dependency dep = dependencyMap.get(entry.getKey());
Stack<Dependency> stackedDependencies = new Stack<>();
sortDependencies(stackedDependencies,dep);
NarClassLoader loader = null;
NarClassLoader depLoader = null;
// test the dependencies to ensure we've loaded them
// and performed a topological sort.
for(Dependency sortedDependency : stackedDependencies) {
depLoader = loaderMap.get(sortedDependency);
if (depLoader == null) {
File path = fileMap.get(sortedDependency.artifactName);
BundleDetails deets = bundleMap.get(sortedDependency.artifactName);
if (deets.getDependencyCoordinate() == null){
loader = null;
}
else
loader = loaderMap.get(deets.getDependencyCoordinate().getId());
depLoader = new NarClassLoader(path, loader == null ? parent : loader);
loaderMap.put(sortedDependency.artifactName, depLoader);
}
}
NarClassLoader thisLoaader = loaderMap.get(entry.getKey());
discoverAndLoad(new Bundle(entry.getValue(), thisLoaader));
} catch (ClassNotFoundException e) {
logger.error("Could not create NarClassLoader",e);
} catch (Throwable e) {
logger.error("Could not create NarClassLoader",e);
}
});
}