ClassLoaderFileSystem.java
/***************************************************************************
Copyright 2013 Emily Estes
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
***************************************************************************/
package net.metanotion.io;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/** Use a Java ClassLoader as a filesystem(via the getResourceAsStream method).
At present this class is VERY limited, as it provides no real "navigation" features for listing folders
and their files. Also this is a "read only" file system. Note: This class has some unresolved bugs
and needs some work. */
public final class ClassLoaderFileSystem implements FileSystem<File> {
private static enum PROPERTIES {
CanRead {
@Override public Object getAttribute(final ClassLoaderFileSystem clfs, final CLFile f) { return true; }
},
CanWrite {
@Override public Object getAttribute(final ClassLoaderFileSystem clfs, final CLFile f) { return false; }
},
ReadOnly {
@Override public Object getAttribute(final ClassLoaderFileSystem clfs, final CLFile f) { return true; }
},
MIMEType {
@Override public Object getAttribute(final ClassLoaderFileSystem clfs, final CLFile f) {
return clfs.mimeUtil.getMIMEType(f.url);
}
};
abstract Object getAttribute(ClassLoaderFileSystem clfs, CLFile f);
}
private static final class CLFile implements File<File> {
private final ClassLoaderFileSystem clfs;
private final String[] name;
private final String url;
public CLFile(ClassLoaderFileSystem clfs, String[] name, String url) {
this.clfs = clfs;
this.name = name;
this.url = url;
}
@Override public int compareTo(final File f) {
if (((CLFile) f).clfs != clfs) {
throw new BadFileException("Only files from the same FileSystem object can be compared.");
}
return this.url.compareTo(((CLFile) f).url);
}
@Override public boolean equals(final Object o) {
if(o==this) { return true; }
if(o==null) { return false; }
if(!(o instanceof CLFile)) { return false; }
final CLFile file = (CLFile) o;
if(file.clfs != this.clfs) { return false; }
return this.url.equals(file.url);
}
@Override public int hashCode() { return clfs.hashCode() + url.hashCode(); }
@Override public Object getAttribute(final String attrib) {
return ClassLoaderFileSystem.PROPERTIES.valueOf(attrib).getAttribute(clfs, this);
}
@Override public Iterator<String> listAttributes() {
final ArrayList<String> props = new ArrayList<>();
for(ClassLoaderFileSystem.PROPERTIES p: ClassLoaderFileSystem.PROPERTIES.values()) { props.add(p.toString()); }
return props.iterator();
}
@Override public boolean exists() {
try (final java.io.InputStream is = clfs.cl.getResourceAsStream(url.substring(1))) {
if(is == null) { return false; }
is.read();
} catch (final IOException e) {
return false;
}
return true;
}
@Override public long length() { throw new UnsupportedOperationException(); }
@Override public java.io.InputStream openInput() {
final java.io.InputStream is = clfs.cl.getResourceAsStream(this.url.substring(1));
if(is == null) { throw new FileNotFoundException(); }
return is;
}
}
private final List<String> root;
private final String rootFull;
private final MIMEUtil mimeUtil;
private final ClassLoader cl;
/** Create a new file system object that is backed by a class loader from which files are loaded from.
@param cl The class loader that resources will be loaded from.
*/
public ClassLoaderFileSystem(final ClassLoader cl) { this(cl, FileSystem.SEPARATOR, new MIMEUtil()); }
/** Create a new file system object that is backed by a class loader from which files are loaded from.
@param cl The class loader that resources will be loaded from.
@param base The root prefix added to all resources loaded from this file system.
*/
public ClassLoaderFileSystem(final ClassLoader cl, final String base) { this(cl, base, new MIMEUtil()); }
/** Create a new file system object that is backed by a class loader from which files are loaded from.
@param cl The class loader that resources will be loaded from.
@param base The root prefix added to all resources loaded from this file system.
@param mimeUtil The MIME util instance used to determine the MIME type of files.
*/
public ClassLoaderFileSystem(final ClassLoader cl, String base, final MIMEUtil mimeUtil) {
this.mimeUtil = mimeUtil;
this.root = FileSystemUtils.getRoot(base);
this.rootFull = FileSystemUtils.join(this.root);
this.cl = cl;
}
@Override public File get(final String url) {
final List<String> file = FileSystemUtils.getFile(url, root);
return new CLFile(this, file.toArray(new String[file.size()]), FileSystemUtils.join(file));
}
}