diff --git a/core/src/main/java/hudson/model/DirectoryBrowserSupport.java b/core/src/main/java/hudson/model/DirectoryBrowserSupport.java index b5f3e77930bb6f10828db272cf3a3c7e8701beda..695547d07231958f78a153c43c2513d6e3a6ea34 100644 --- a/core/src/main/java/hudson/model/DirectoryBrowserSupport.java +++ b/core/src/main/java/hudson/model/DirectoryBrowserSupport.java @@ -25,6 +25,7 @@ package hudson.model; import hudson.FilePath; import hudson.Util; +import hudson.remoting.Callable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -34,10 +35,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; -import java.util.IdentityHashMap; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; @@ -252,7 +251,7 @@ public final class DirectoryBrowserSupport implements HttpResponse { } else if(serveDirIndex) { // serve directory index - glob = buildChildPaths(baseFile, req.getLocale()); + glob = baseFile.run(new BuildChildPaths(baseFile, req.getLocale())); } if(glob!=null) { @@ -431,7 +430,6 @@ public final class DirectoryBrowserSupport implements HttpResponse { private static final class FileComparator implements Comparator { private Collator collator; - private final Map isDirCache = new IdentityHashMap(); FileComparator(Locale locale) { this.collator = Collator.getInstance(locale); @@ -445,18 +443,9 @@ public final class DirectoryBrowserSupport implements HttpResponse { return this.collator.compare(lhs.getName(), rhs.getName()); } - private boolean isDirectory(VirtualFile f) throws IOException { - Boolean known = isDirCache.get(f); - if (known == null) { - known = f.isDirectory(); - isDirCache.put(f, known); - } - return known; - } - private int dirRank(VirtualFile f) { try { - if(isDirectory(f)) return 0; + if(f.isDirectory()) return 0; else return 1; } catch (IOException ex) { return 0; @@ -464,6 +453,17 @@ public final class DirectoryBrowserSupport implements HttpResponse { } } + private static final class BuildChildPaths implements Callable>,IOException> { + private final VirtualFile cur; + private final Locale locale; + BuildChildPaths(VirtualFile cur, Locale locale) { + this.cur = cur; + this.locale = locale; + } + @Override public List> call() throws IOException { + return buildChildPaths(cur, locale); + } + } /** * Builds a list of list of {@link Path}. The inner * list of {@link Path} represents one child item to be shown diff --git a/core/src/main/java/jenkins/util/VirtualFile.java b/core/src/main/java/jenkins/util/VirtualFile.java index e0180f6dedecca34f4be3625525c7e7387b48fbc..1a54d08545e0450a6125f417948a7275b669c3d2 100644 --- a/core/src/main/java/jenkins/util/VirtualFile.java +++ b/core/src/main/java/jenkins/util/VirtualFile.java @@ -26,6 +26,7 @@ package jenkins.util; import hudson.FilePath; import hudson.model.DirectoryBrowserSupport; +import hudson.remoting.Callable; import hudson.remoting.Channel; import hudson.remoting.VirtualChannel; import hudson.util.DirScanner; @@ -34,6 +35,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.Serializable; import java.net.URI; import java.util.ArrayList; import java.util.List; @@ -56,7 +58,7 @@ import javax.annotation.Nonnull; * @see FilePath * @since 1.532 */ -public abstract class VirtualFile implements Comparable { +public abstract class VirtualFile implements Comparable, Serializable { /** * Gets the base name, meaning just the last portion of the path name without any @@ -184,13 +186,34 @@ public abstract class VirtualFile implements Comparable { return toURI().toString(); } + /** + * Does some calculations in batch. + * For a remote file, this can be much faster than doing the corresponding operations one by one as separate requests. + * The default implementation just calls the block directly. + * @param a value type + * @param the exception type + * @param callable something to run all at once (only helpful if any mentioned files are on the same system) + * @return the callable result + * @throws IOException if remote communication failed + * @since 1.554 + */ + public V run(Callable callable) throws IOException { + return callable.call(); + } + /** * Creates a virtual file wrapper for a local file. * @param f a disk file (need not exist) * @return a wrapper */ public static VirtualFile forFile(final File f) { - return new VirtualFile() { + return new FileVF(f); + } + private static final class FileVF extends VirtualFile { + private final File f; + FileVF(File f) { + this.f = f; + } @Override public String getName() { return f.getName(); } @@ -238,7 +261,6 @@ public abstract class VirtualFile implements Comparable { @Override public InputStream open() throws IOException { return new FileInputStream(f); } - }; } /** @@ -247,7 +269,13 @@ public abstract class VirtualFile implements Comparable { * @return a wrapper */ public static VirtualFile forFilePath(final FilePath f) { - return new VirtualFile() { + return new FilePathVF(f); + } + private static final class FilePathVF extends VirtualFile { + private final FilePath f; + FilePathVF(FilePath f) { + this.f = f; + } @Override public String getName() { return f.getName(); } @@ -328,7 +356,13 @@ public abstract class VirtualFile implements Comparable { @Override public InputStream open() throws IOException { return f.read(); } - }; + @Override public V run(Callable callable) throws IOException { + try { + return f.act(callable); + } catch (InterruptedException x) { + throw (IOException) new IOException(x.toString()).initCause(x); + } + } } private static final class Scanner implements FilePath.FileCallable { private final String glob;