thredds.filesystem.ControllerOS Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 1998 - 2011. University Corporation for Atmospheric Research/Unidata
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package thredds.filesystem;
import thredds.inventory.CollectionConfig;
import thredds.inventory.MController;
import thredds.inventory.MFile;
import javax.annotation.concurrent.ThreadSafe;
import java.io.File;
import java.util.*;
/**
* Implements an MController without caching, reading from OS each time.
* recheck is ignored (always true)
*
* @author caron
* @since Jun 25, 2009
*/
@ThreadSafe
public class ControllerOS implements MController {
static private org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ControllerOS.class);
////////////////////////////////////////
public ControllerOS() {
}
@Override
public Iterator getInventoryAll(CollectionConfig mc, boolean recheck) {
String path = mc.getDirectoryName();
if (path.startsWith("file:")) {
path = path.substring(5);
}
File cd = new File(path);
if (!cd.exists()) return null;
if (!cd.isDirectory()) return null;
return new FilteredIterator(mc, new MFileIteratorAll(cd), false);
}
@Override
public Iterator getInventoryTop(CollectionConfig mc, boolean recheck) {
String path = mc.getDirectoryName();
if (path.startsWith("file:")) {
path = path.substring(5);
}
File cd = new File(path);
if (!cd.exists()) return null;
if (!cd.isDirectory()) return null;
return new FilteredIterator(mc, new MFileIterator(cd), false); // removes subdirs
}
public Iterator getSubdirs(CollectionConfig mc, boolean recheck) {
String path = mc.getDirectoryName();
if (path.startsWith("file:")) {
path = path.substring(5);
}
File cd = new File(path);
if (!cd.exists()) return null;
if (!cd.isDirectory()) return null;
return new FilteredIterator(mc, new MFileIterator(cd), true); // return only subdirs
}
public void close() {
} // NOOP
////////////////////////////////////////////////////////////
// handles filtering and removing/including subdirectories
private static class FilteredIterator implements Iterator {
private Iterator orgIter;
private CollectionConfig mc;
private boolean wantDirs;
private MFile next;
FilteredIterator(CollectionConfig mc, Iterator iter, boolean wantDirs) {
this.orgIter = iter;
this.mc = mc;
this.wantDirs = wantDirs;
}
public boolean hasNext() {
next = nextFilteredFile(); /// 7
return (next != null);
}
public MFile next() {
if (next == null) throw new NoSuchElementException();
return next;
}
public void remove() {
throw new UnsupportedOperationException();
}
private MFile nextFilteredFile() {
if (orgIter == null) return null;
if (!orgIter.hasNext()) return null;
MFile pdata = orgIter.next();
while ((pdata.isDirectory() != wantDirs) || !mc.accept(pdata)) { // skip directories, and filter
if (!orgIter.hasNext()) return null; /// 6
pdata = orgIter.next();
}
return pdata;
}
}
// returns everything in the current directory
private static class MFileIterator implements Iterator {
List files;
int count = 0;
MFileIterator(File dir) {
File[] f = dir.listFiles();
if (f == null) { // null on i/o error
logger.warn("I/O error on " + dir.getPath());
throw new IllegalStateException("dir.getPath() returned null on " + dir.getPath());
} else
files = Arrays.asList(f);
}
MFileIterator(List files) {
this.files = files;
}
public boolean hasNext() {
return count < files.size();
}
public MFile next() {
File cfile = files.get(count++);
return new MFileOS(cfile);
}
public void remove() {
throw new UnsupportedOperationException();
}
}
// recursively scans everything in the directory and in subdirectories, depth first (leaves before subdirs)
private static class MFileIteratorAll implements Iterator {
Queue traverse;
Traversal currTraversal;
Iterator currIter;
MFileIteratorAll(File top) {
traverse = new LinkedList<>();
currTraversal = new Traversal(top);
}
public boolean hasNext() {
if (currIter == null) {
currIter = getNextIterator();
if (currIter == null) {
return false;
}
}
if (!currIter.hasNext()) {
currIter = getNextIterator(); /// 5
return hasNext();
}
return true;
}
public MFile next() {
return currIter.next();
}
private Iterator getNextIterator() {
if (!currTraversal.leavesAreDone) {
currTraversal.leavesAreDone = true;
return new MFileIterator(currTraversal.fileList); // look for leaves in the current directory. may be empty.
} else {
if ((currTraversal.subdirIterator != null) && currTraversal.subdirIterator.hasNext()) { // has subdirs
File nextDir = currTraversal.subdirIterator.next(); /// NCDC gets null
traverse.add(currTraversal); // keep track of current traversal
currTraversal = new Traversal(nextDir); /// 2
return getNextIterator();
} else {
if (traverse.peek() == null) return null;
currTraversal = traverse.remove();
return getNextIterator(); // 3 and 4 iteration
}
}
}
public void remove() {
throw new UnsupportedOperationException();
}
}
// traversal of one directory
private static class Traversal {
List fileList; // list of files
Iterator subdirIterator; // list of subdirs
boolean leavesAreDone = false; // when all the files are done, start on the subdirs
Traversal(File dir) {
fileList = new ArrayList<>();
if (dir == null) return; // LOOK WHY
if (dir.listFiles() == null) return;
if (logger.isTraceEnabled()) logger.trace("List Directory "+dir);
List subdirList = new ArrayList<>();
File[] files = dir.listFiles();
if (files != null)
for (File f : files) { /// 1
if (f == null) {
logger.warn(" NULL FILE in directory "+dir);
continue;
}
if (logger.isTraceEnabled()) logger.trace(" File "+f);
if (f.isDirectory())
subdirList.add(f);
else
fileList.add(f);
}
if (subdirList.size() > 0)
this.subdirIterator = subdirList.iterator();
}
}
}