001/** 002 * The contents of this file are subject to the license and copyright 003 * detailed in the LICENSE and NOTICE files at the root of the source 004 * tree. 005 * 006 */ 007package org.fcrepo.migration.foxml; 008 009import java.io.File; 010import java.io.FileFilter; 011import java.io.FileNotFoundException; 012import java.util.ArrayList; 013import java.util.Arrays; 014import java.util.Iterator; 015import java.util.List; 016import java.util.Stack; 017 018import javax.xml.stream.XMLStreamException; 019 020import org.fcrepo.migration.FedoraObjectProcessor; 021 022/** 023 * A depth-first-search iteration over a tree of files that exposes them as FedoraObjectProcessors. 024 * Each file in the tree is expected to be a FOXML file. This implementation likely minimizes 025 * memory usage for the expected organization of FOXML files on disk. 026 * @author mdurbin 027 */ 028public class FoxmlDirectoryDFSIterator implements Iterator<FedoraObjectProcessor> { 029 030 private List<File> current; 031 private Stack<List<File>> stack; 032 033 private InternalIDResolver resolver; 034 private URLFetcher fetcher; 035 036 private String localFedoraServer; 037 038 private FileFilter fileFilter; 039 040 /** 041 * foxml directory DFS iterator. 042 * @param root the root file 043 * @param fetcher the fetcher 044 * @param localFedoraServer uri to local fedora server 045 * @param fileFilter a FileFilter that defined which files should be included 046 * in this Iterator. 047 */ 048 public FoxmlDirectoryDFSIterator(final File root, final URLFetcher fetcher, final String localFedoraServer, 049 final FileFilter fileFilter) { 050 stack = new Stack<List<File>>(); 051 current = new ArrayList<File>(Arrays.asList(root.listFiles())); 052 this.fetcher = fetcher; 053 this.localFedoraServer = localFedoraServer; 054 this.fileFilter = fileFilter; 055 } 056 057 /** 058 * foxml directory DFS iterator with three parameters 059 * @param root the root file 060 * @param resolver the resolver 061 * @param fetcher the fetcher 062 * @param localFedoraServer the domain and port for the server that hosted the fedora objects in the format 063 * "localhost:8080". 064 * @param fileFilter a FileFilter that defined which files should be included 065 * in this Iterator. 066 */ 067 public FoxmlDirectoryDFSIterator(final File root, final InternalIDResolver resolver, final URLFetcher fetcher, 068 final String localFedoraServer, final FileFilter fileFilter) { 069 this(root, fetcher, localFedoraServer, fileFilter); 070 this.resolver = resolver; 071 } 072 073 private boolean advanceToNext() { 074 while (current.size() > 0 || stack.size() > 0) { 075 if (current.isEmpty()) { 076 current = stack.pop(); 077 } else { 078 final File first = current.get(0); 079 if (first.isFile()) { 080 if (this.fileFilter.accept(first)) { 081 return true; 082 } else { 083 // exclude the current file and get the next one... 084 current.remove(0); 085 return advanceToNext(); 086 } 087 } else { 088 final File directory = current.remove(0); 089 stack.push(current); 090 current = new ArrayList<File>(Arrays.asList(directory.listFiles())); 091 } 092 } 093 } 094 return false; 095 } 096 097 @Override 098 public boolean hasNext() { 099 return advanceToNext(); 100 } 101 102 @Override 103 public FedoraObjectProcessor next() { 104 if (!advanceToNext()) { 105 throw new IllegalStateException(); 106 } else { 107 final File currentFile = current.remove(0); 108 try { 109 return new FoxmlInputStreamFedoraObjectProcessor( 110 currentFile, fetcher, resolver, localFedoraServer); 111 } catch (final XMLStreamException e) { 112 throw new RuntimeException(currentFile.getPath() + " doesn't appear to be an XML file." 113 + (e.getMessage() != null ? " (" + e.getMessage() + ")" : "")); 114 } catch (final FileNotFoundException e) { 115 throw new RuntimeException(e); 116 } 117 } 118 } 119 120 @Override 121 public void remove() { 122 throw new UnsupportedOperationException(); 123 } 124 125}