Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removed depth when searching extension jars #1461

Merged
merged 3 commits into from
Feb 22, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,20 @@
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
*
* QuPath 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
*
* You should have received a copy of the GNU General Public License
* along with QuPath. If not, see <https://www.gnu.org/licenses/>.
* #L%
*/

package qupath.lib.gui;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.FileVisitOption;
Expand All @@ -32,25 +31,23 @@
import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Stream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* {@link ClassLoader} for loading QuPath extensions and other jars from the user directory.
*
*
* @author Pete Bankhead
*/
public class ExtensionClassLoader extends URLClassLoader {

private static final Logger logger = LoggerFactory.getLogger(ExtensionClassLoader.class);

private static int MAX_EXTENSION_JARS_DEPTH = 3; // non-final to be editable with Groovy
private static ExtensionClassLoader INSTANCE = null;

private Supplier<Path> extensionsDirectorySupplier;

private Set<Path> loadedJars = new HashSet<>();

private final Supplier<Path> extensionsDirectorySupplier;
private final Set<Path> loadedJars = new HashSet<>();
private boolean isClosed = false;

private ExtensionClassLoader(Supplier<Path> extensionsDirectorySupplier) {
Expand All @@ -63,9 +60,9 @@ private ExtensionClassLoader(Supplier<Path> extensionsDirectorySupplier) {
* Get a singleton instance of the {@link ExtensionClassLoader}.
* @return
* @since v0.5.0
*
* @implNote This was introduced in v0.5.0 to hide the constructor and avoid needing to request
* the classloader via QuPathGUI. <i>However</i> the behavior may change in the future, so as to
*
* @implNote This was introduced in v0.5.0 to hide the constructor and avoid needing to request
* the classloader via QuPathGUI. <i>However</i> the behavior may change in the future, so as to
* avoid relying upon a single static instance.
*/
public static ExtensionClassLoader getInstance() {
Expand All @@ -86,9 +83,9 @@ private static Path getDefaultExtensionsDirectory() {

/**
* Directory containing extensions.
*
*
* This can contain any jars - all will be added to the search path when starting QuPath.
*
*
* @return
*/
public Path getExtensionsDirectory() {
Expand All @@ -106,24 +103,25 @@ public void refresh() {
}
if (!Files.exists(dirExtensions)) {
logger.debug("No extensions directory exists at {}", dirExtensions);
return;
return;
}
if (!Files.isDirectory(dirExtensions)) {
logger.error("Invalid extensions directory! '{}' is not a directory.", dirExtensions);
return;
}
int depth = 1;
try {
Files.walk(dirExtensions, depth, FileVisitOption.FOLLOW_LINKS)
.filter(this::isJarFile)
.map(p -> p.toAbsolutePath())
.distinct()
.forEach(this::addJarFile);
try (Stream<Path> walk = Files.walk(dirExtensions, MAX_EXTENSION_JARS_DEPTH, FileVisitOption.FOLLOW_LINKS)) {
walk
.filter(this::isJarFile)
.map(Path::toAbsolutePath)
.distinct()
.forEach(this::addJarFile);
}
} catch (IOException e) {
logger.error("Exception refreshing extensions: " + e.getLocalizedMessage(), e);
}
}

private void addJarFile(Path path) {
try {
if (loadedJars.add(path)) {
Expand All @@ -150,6 +148,5 @@ public void close() throws IOException {
private boolean isJarFile(Path path) {
return Files.isRegularFile(path) && path.getFileName().toString().toLowerCase().endsWith(".jar");
}


}