Skip to content

Commit 8532e82

Browse files
authored
Merge pull request #275 from scijava/more-handles-multifile
Add browsing support for Locations
2 parents 172009d + 62bf4a4 commit 8532e82

File tree

3 files changed

+168
-3
lines changed

3 files changed

+168
-3
lines changed
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2017 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck
7+
* Institute of Molecular Cell Biology and Genetics, University of
8+
* Konstanz, and KNIME GmbH.
9+
* %%
10+
* Redistribution and use in source and binary forms, with or without
11+
* modification, are permitted provided that the following conditions are met:
12+
*
13+
* 1. Redistributions of source code must retain the above copyright notice,
14+
* this list of conditions and the following disclaimer.
15+
* 2. Redistributions in binary form must reproduce the above copyright notice,
16+
* this list of conditions and the following disclaimer in the documentation
17+
* and/or other materials provided with the distribution.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
23+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+
* POSSIBILITY OF SUCH DAMAGE.
30+
* #L%
31+
*/
32+
33+
package org.scijava.io.location;
34+
35+
import java.io.IOException;
36+
import java.util.Collections;
37+
import java.util.Set;
38+
39+
/**
40+
* A {@link Location} that offers methods to browse other locations relative to
41+
* it.
42+
*
43+
* @author Gabriel Einsdorf
44+
* @author Curtis Rueden
45+
*/
46+
public interface BrowsableLocation extends Location {
47+
48+
/**
49+
* Obtains a location pointing to the parent directory of this one.
50+
*
51+
* @return the parent location of this one, or <code>null</code> if this
52+
* location has no parent.
53+
* @throws IOException if something goes wrong obtaining the parent.
54+
*/
55+
BrowsableLocation parent() throws IOException;
56+
57+
/**
58+
* Obtains a collection of locations for whom this location is the parent.
59+
* Note that this will only succeed if calls to {@link #isDirectory()} on this
60+
* location return <code>true</code>.
61+
*
62+
* @return A set containing the children of this location, or
63+
* {@link Collections#EMPTY_SET} if this location has no children.
64+
* @throws IOException if something goes wrong obtaining the children.
65+
* @throws IllegalArgumentException if this location is not a directory (i.e.,
66+
* {@link #isDirectory()} returns false).
67+
*/
68+
Set<BrowsableLocation> children() throws IOException;
69+
70+
/**
71+
* Obtains a location relative to this one, which will be configured
72+
* like the current location, but point to a the file specified by the
73+
* <code>path</code> parameter.
74+
*
75+
* @param path the relative path of the desired location.
76+
* @return A location that points to the specified file location.
77+
* @throws IOException if something goes wrong obtaining the sibling
78+
*/
79+
BrowsableLocation sibling(String path) throws IOException;
80+
81+
/**
82+
* Tests whether this location is a <b>directory</b>, meaning that it can have
83+
* children. It is recommended to use this method before calling
84+
* {@link #child(String)} or {@link #children()}, to ensure those calls
85+
* succeed.
86+
*
87+
* @return True iff the location represents a directory.
88+
*/
89+
boolean isDirectory();
90+
91+
/**
92+
* Obtains a location with the given name, for whom this location is the
93+
* parent. Note that this will only succeed if calls to {@link #isDirectory()}
94+
* on this location return <code>true</code>.
95+
*
96+
* @param name the name of the child
97+
* @return a location pointing to the child
98+
* @throws IOException if something goes wrong obtaining the child.
99+
* @throws IllegalArgumentException if this location is not a directory (i.e.,
100+
* {@link #isDirectory()} returns false).
101+
*/
102+
BrowsableLocation child(String name) throws IOException;
103+
}

src/main/java/org/scijava/io/location/FileLocation.java

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,21 @@
3333
package org.scijava.io.location;
3434

3535
import java.io.File;
36+
import java.io.IOException;
3637
import java.net.URI;
38+
import java.util.Collections;
39+
import java.util.HashSet;
40+
import java.util.Set;
3741

3842
/**
3943
* {@link Location} backed by a {@link File} on disk.
4044
*
4145
* @author Curtis Rueden
46+
* @author Gabriel Einsdorf
4247
*/
43-
public class FileLocation extends AbstractLocation {
48+
public class FileLocation extends AbstractLocation implements
49+
BrowsableLocation
50+
{
4451

4552
private final File file;
4653

@@ -75,4 +82,47 @@ public String getName() {
7582
return file.getName();
7683
}
7784

85+
// -- BrowsableLocation methods --
86+
87+
@Override
88+
public FileLocation parent() throws IOException {
89+
return new FileLocation(file.getParentFile());
90+
}
91+
92+
@Override
93+
public Set<BrowsableLocation> children() throws IOException {
94+
validateDirectory();
95+
final File[] files = file.listFiles();
96+
if (files == null) return Collections.emptySet();
97+
98+
final Set<BrowsableLocation> out = new HashSet<>(files.length);
99+
for (final File child : files) {
100+
out.add(new FileLocation(child));
101+
}
102+
return out;
103+
}
104+
105+
@Override
106+
public FileLocation sibling(final String path) {
107+
return new FileLocation(new File(file.getParentFile(), path));
108+
}
109+
110+
@Override
111+
public FileLocation child(final String name) {
112+
validateDirectory();
113+
return new FileLocation(new File(file, name));
114+
}
115+
116+
@Override
117+
public boolean isDirectory() {
118+
return file.isDirectory();
119+
}
120+
121+
// -- Helper methods --
122+
123+
private void validateDirectory() {
124+
if (isDirectory()) return;
125+
throw new IllegalArgumentException(
126+
"This location does not point to a directory!");
127+
}
78128
}

src/main/java/org/scijava/io/location/Location.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,20 @@ default URI getURI() {
7171
* @return The name, or an empty string if no name is available.
7272
*/
7373
default String getName() {
74-
final URI uri = getURI();
75-
return uri == null ? "" : uri.toString();
74+
return defaultName();
7675
}
7776

77+
/**
78+
* Gets the default name used when no explicit name is assigned.
79+
* <p>
80+
* Note: this is mostly intended for debugging, since most kinds of
81+
* {@code Location} will assign some non-default name. But in cases where that
82+
* does not occur, this value can be useful to detect the situation.
83+
* </p>
84+
*
85+
* @return The default name string.
86+
*/
87+
default String defaultName() {
88+
return "Location.defaultName";
89+
}
7890
}

0 commit comments

Comments
 (0)