diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/AbstractGhidraHeadlessIntegrationTest.java b/Ghidra/Features/Base/src/main/java/ghidra/test/AbstractGhidraHeadlessIntegrationTest.java index 8ecf478a86..3a73e21c7a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/test/AbstractGhidraHeadlessIntegrationTest.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/AbstractGhidraHeadlessIntegrationTest.java @@ -533,8 +533,8 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock public static void replaceService(Class service, Class replacement) { - List> extentions = - (List>) getInstanceField("extensionPoints", ClassSearcher.class); + Set> extentions = + (Set>) getInstanceField("extensionPoints", ClassSearcher.class); HashSet> set = new HashSet<>(extentions); Iterator> iterator = set.iterator(); while (iterator.hasNext()) { @@ -546,7 +546,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock set.add(replacement); - List> newExtensionPoints = new ArrayList<>(set); + Set> newExtensionPoints = new HashSet<>(set); setInstanceField("extensionPoints", ClassSearcher.class, newExtensionPoints); } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassDir.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassDir.java index 0137acf169..3798f08c99 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassDir.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassDir.java @@ -16,8 +16,7 @@ package ghidra.util.classfinder; import java.io.File; -import java.io.FileNotFoundException; -import java.util.*; +import java.util.Set; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; @@ -26,35 +25,16 @@ class ClassDir { private String dirPath; private File dir; - private List children = new ArrayList<>(); + private ClassPackage classPackage; ClassDir(String dirPath, TaskMonitor monitor) throws CancelledException { this.dirPath = dirPath; this.dir = new File(dirPath); - children.add(new ClassPackage(dir, "", monitor)); - } - - void rescan(TaskMonitor monitor) throws CancelledException { - - Iterator classPackageIterator = children.iterator(); - while (classPackageIterator.hasNext()) { - ClassPackage pkg = classPackageIterator.next(); - try { - pkg.rescan(monitor); - } - catch (FileNotFoundException e) { - classPackageIterator.remove(); - } - } + classPackage = new ClassPackage(dir, "", monitor); } void getClasses(Set> set, TaskMonitor monitor) throws CancelledException { - Iterator classPackageIterator = children.iterator(); - while (classPackageIterator.hasNext()) { - monitor.checkCanceled(); - ClassPackage pkg = classPackageIterator.next(); - pkg.getClasses(set, monitor); - } + classPackage.getClasses(set, monitor); } String getDirPath() { diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassFinder.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassFinder.java index 1905afc1d2..81fea0f39b 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassFinder.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassFinder.java @@ -29,7 +29,7 @@ import ghidra.util.task.TaskMonitor; import utility.module.ModuleUtilities; /** - * Finds classes in the classPath that match one of the filter classes. + * Finds extension classes in the classpath */ public class ClassFinder { static final Logger log = LogManager.getLogger(ClassFinder.class); @@ -37,10 +37,8 @@ public class ClassFinder { private static List> FILTER_CLASSES = Collections.unmodifiableList(Arrays.asList(ExtensionPoint.class)); - private List classDirs = new ArrayList<>(); - private List classJars = new ArrayList<>(); - - private Map>> classesByName; + private Set classDirs = new HashSet<>(); + private Set classJars = new HashSet<>(); public ClassFinder(List searchPaths, TaskMonitor monitor) throws CancelledException { initialize(searchPaths, monitor); @@ -48,46 +46,9 @@ public class ClassFinder { private void initialize(List searchPaths, TaskMonitor monitor) throws CancelledException { - classDirs.clear(); - classJars.clear(); - reconcileClasses(searchPaths, monitor); - } - - private void reconcileClasses(List searchPaths, TaskMonitor monitor) - throws CancelledException { Set pathSet = new LinkedHashSet<>(searchPaths); - Iterator dirs = classDirs.iterator(); - while (dirs.hasNext()) { - monitor.checkCanceled(); - ClassDir classDir = dirs.next(); - String dirPath = classDir.getDirPath(); - if (!pathSet.contains(dirPath)) { - log.trace(dirPath + " dropped from previous classpath"); - dirs.remove(); - } - else { - classDir.rescan(monitor); - pathSet.remove(dirPath); - } - } - - Iterator jars = classJars.iterator(); - while (jars.hasNext()) { - monitor.checkCanceled(); - ClassJar classJar = jars.next(); - String jarPath = classJar.getJarPath(); - if (!pathSet.contains(jarPath)) { - log.trace(jarPath + " dropped from previous classpath"); - jars.remove(); - } - else { - classJar.rescan(monitor); - pathSet.remove(jarPath); - } - } - Iterator pathIterator = pathSet.iterator(); while (pathIterator.hasNext()) { monitor.checkCanceled(); @@ -109,47 +70,23 @@ public class ClassFinder { classDirs.add(new ClassDir(path, monitor)); } } - } - public List> getClasses(Class filterClass, TaskMonitor monitor) - throws CancelledException { - if (classesByName == null) { - Map>> map = new HashMap<>(); + Set> getClasses(TaskMonitor monitor) throws CancelledException { - Set> classSet = new HashSet<>(); - Iterator classDirIterator = classDirs.iterator(); - while (classDirIterator.hasNext()) { - monitor.checkCanceled(); - ClassDir classDir = classDirIterator.next(); - classDir.getClasses(classSet, monitor); - } - Iterator classJarsIterator = classJars.iterator(); - while (classJarsIterator.hasNext()) { - monitor.checkCanceled(); - ClassJar classJar = classJarsIterator.next(); - classJar.getClasses(classSet, monitor); - } + Set> classes = new HashSet<>(); - for (Class filterClasse : FILTER_CLASSES) { - monitor.checkCanceled(); - List> list = new ArrayList<>(); - Iterator> classSetIterator = classSet.iterator(); - while (classSetIterator.hasNext()) { - Class c = classSetIterator.next(); - if (filterClasse.isAssignableFrom(c)) { - list.add(c); - } - } - - map.put(filterClasse.getName(), list); - } - - classesByName = map; + for (ClassDir dir : classDirs) { + monitor.checkCanceled(); + dir.getClasses(classes, monitor); } - List> classes = classesByName.get(filterClass.getName()); - return classes != null ? classes : Collections.emptyList(); + for (ClassJar jar : classJars) { + monitor.checkCanceled(); + jar.getClasses(classes, monitor); + } + + return classes; } /*package*/ static Class loadExtensionPoint(String path, String fullName) { diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassJar.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassJar.java index 652375d620..4200075f27 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassJar.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassJar.java @@ -40,9 +40,8 @@ class ClassJar { Pattern.compile(".*/(.*)/(?:lib|build/libs)/(.+).jar"); private String path; - private long time; private Set classNameList = new HashSet<>(); - private Set> classes = null; + private Set> classes = new HashSet<>(); ClassJar(String path, TaskMonitor monitor) throws CancelledException { this.path = path; @@ -50,45 +49,13 @@ class ClassJar { scan(monitor); } - String getJarPath() { - return path; - } - - boolean rescan(TaskMonitor monitor) throws CancelledException { - File file = new File(path); - if (file.lastModified() != time) { - scan(monitor); - return true; - } - return false; - } - - void getClasses(Set> list, TaskMonitor monitor) { - if (classes == null) { - ClassLoader classLoader = ClassSearcher.class.getClassLoader(); - classes = new HashSet<>(); - Iterator iter = classNameList.iterator(); - while (iter.hasNext()) { - String name = iter.next(); - try { - monitor.setMessage("loading class: " + name); - classes.add(Class.forName(name, true, classLoader)); - } - catch (Throwable t) { - Msg.showError(this, null, "Error loading class", - "Error loading class " + name + ":", t); - } - } - } - list.addAll(classes); + void getClasses(Set> set, TaskMonitor monitor) { + set.addAll(classes); } private void scan(TaskMonitor monitor) throws CancelledException { - classes = new HashSet<>(); - classNameList.clear(); File file = new File(path); - time = file.lastModified(); try (JarFile jarFile = new JarFile(file)) { diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassPackage.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassPackage.java index 1effafa8c5..914da5d02c 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassPackage.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassPackage.java @@ -15,7 +15,8 @@ */ package ghidra.util.classfinder; -import java.io.*; +import java.io.File; +import java.io.FileFilter; import java.util.*; import ghidra.util.Msg; @@ -27,53 +28,47 @@ class ClassPackage { private static final FileFilter CLASS_FILTER = pathname -> pathname.getName().endsWith(".class"); - private Set classNames = new HashSet<>(); - private Set> classes = null; - private List children = new ArrayList<>(); + private Set> classes = new HashSet<>(); + private Set children = new HashSet<>(); private File rootDir; + private File packageDir; private String packageName; ClassPackage(File rootDir, String packageName, TaskMonitor monitor) throws CancelledException { monitor.checkCanceled(); this.rootDir = rootDir; this.packageName = packageName; + this.packageDir = getPackageDir(rootDir, packageName); scanClasses(); scanSubPackages(monitor); } private void scanClasses() { - classNames.clear(); - classes = new HashSet<>(); - String path = rootDir.getAbsolutePath(); - List allClassNames = getAllClassNames(); + Set allClassNames = getAllClassNames(); for (String className : allClassNames) { - Class c = ClassFinder.loadExtensionPoint(path, className); if (c != null) { classes.add(c); - classNames.add(c.getName()); } } - } private void scanSubPackages(TaskMonitor monitor) throws CancelledException { - children.clear(); - File dir = getPackageDir(rootDir, packageName); - File[] subdirs = dir.listFiles(); + + File[] subdirs = packageDir.listFiles(); if (subdirs == null) { - Msg.debug(this, "Directory does not exist: " + dir); + Msg.debug(this, "Directory does not exist: " + packageDir); return; } for (File subdir : subdirs) { + monitor.checkCanceled(); if (!subdir.isDirectory()) { continue; } - monitor.checkCanceled(); String pkg = subdir.getName(); if (pkg.contains(".")) { // java can't handle dir names with '.'-- it conflicts with the package structure @@ -89,64 +84,6 @@ class ClassPackage { } } - void rescan(TaskMonitor monitor) throws CancelledException, FileNotFoundException { - - monitor.checkCanceled(); - - scanClasses(); - - File dir = getPackageDir(rootDir, packageName); - String rootPath = rootDir.getAbsolutePath(); - String dirPath = dir.getAbsolutePath(); - dirPath = dirPath.substring(rootPath.length()); - - monitor.setMessage("scanning directory: " + rootDir.getName() + dirPath); - File[] subdirs = dir.listFiles(); - if (subdirs == null) { - Msg.debug(this, "Directory does not exist: " + dir); - return; - } - - Set pkgNames = new HashSet<>(); - for (File subdir : subdirs) { - monitor.checkCanceled(); - if (!subdir.isDirectory()) { - continue; - } - - String name = subdir.getName(); - if (name.contains(".")) { - // java can't handle dir names with '.'-- it conflicts with the package structure - continue; - } - - if (packageName.length() > 0) { - name = packageName + "." + name; - } - pkgNames.add(name); - } - - Iterator classPackageIterator = children.iterator(); - while (classPackageIterator.hasNext()) { - monitor.checkCanceled(); - ClassPackage pkg = classPackageIterator.next(); - if (!pkgNames.contains(pkg.packageName)) { - classPackageIterator.remove(); - } - else { - pkg.rescan(monitor); - pkgNames.remove(pkg.packageName); - } - } - - Iterator packageNameIterator = pkgNames.iterator(); - while (packageNameIterator.hasNext()) { - monitor.checkCanceled(); - String pkgName = packageNameIterator.next(); - children.add(new ClassPackage(rootDir, pkgName, monitor)); - } - } - private File getPackageDir(File lRootDir, String lPackageName) { return new File(lRootDir, lPackageName.replace('.', File.separatorChar)); } @@ -154,22 +91,22 @@ class ClassPackage { void getClasses(Set> set, TaskMonitor monitor) throws CancelledException { set.addAll(classes); - Iterator classPackageIterator = children.iterator(); - while (classPackageIterator.hasNext()) { + Iterator it = children.iterator(); + while (it.hasNext()) { monitor.checkCanceled(); - ClassPackage subPkg = classPackageIterator.next(); + ClassPackage subPkg = it.next(); subPkg.getClasses(set, monitor); } } - private List getAllClassNames() { - File dir = getPackageDir(rootDir, packageName); - File[] files = dir.listFiles(CLASS_FILTER); + private Set getAllClassNames() { + + File[] files = packageDir.listFiles(CLASS_FILTER); if (files == null) { - return Collections.emptyList(); + return Collections.emptySet(); } - List results = new ArrayList<>(files.length); + Set results = new HashSet<>(files.length); for (File file : files) { String name = file.getName(); name = name.substring(0, name.length() - 6); diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java index 8668b315c6..fbd7d0f095 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java @@ -66,7 +66,7 @@ public class ClassSearcher { static final Logger log = LogManager.getLogger(ClassSearcher.class); private static ClassFinder searcher; - private static List> extensionPoints; + private static Set> extensionPoints; private static WeakSet listenerList = WeakDataStructureFactory.createCopyOnReadWeakSet(); @@ -225,13 +225,13 @@ public class ClassSearcher { extensionPoints = null; long t = (new Date()).getTime(); - log.trace("Searching for classes..."); + log.trace("Searching for classes..."); List searchPaths = gatherSearchPaths(); searcher = new ClassFinder(searchPaths, monitor); monitor.setMessage("Loading classes..."); - extensionPoints = searcher.getClasses(ExtensionPoint.class, monitor); + extensionPoints = searcher.getClasses(monitor); log.trace("Found extension classes: " + extensionPoints); if (extensionPoints.isEmpty()) { throw new AssertException("Unable to location extension points!"); @@ -296,7 +296,7 @@ public class ClassSearcher { ResourceFile extensionClassesFile = new ResourceFile(appRoot, "EXTENSION_POINT_CLASSES"); try { List classNames = FileUtilities.getLines(extensionClassesFile); - List> extensionClasses = new ArrayList<>(); + Set> extensionClasses = new HashSet<>(); for (String className : classNames) { try { Class clazz = Class.forName(className); @@ -306,13 +306,12 @@ public class ClassSearcher { Msg.warn(ClassSearcher.class, "Can't load extension point: " + className); } } - extensionPoints = Collections.unmodifiableList(extensionClasses); + extensionPoints = Collections.unmodifiableSet(extensionClasses); } catch (IOException e) { throw new AssertException("Got unexpected IOException ", e); } - } private static void loadExtensionPointSuffixes() {