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