001 package ps6; 002 003 import ps4.StreetSegment; 004 005 import java.io.*; 006 import java.util.*; 007 008 /** 009 * A StreetSegReader reads StreetSegments from a set of Tiger Databases. 010 * 011 * <p> Tiger Databases are produced and maintained by the <a 012 * href="http://tiger.census.gov/">U.S. Census Bureau</a>. 013 * 014 * <p> Tiger Databases are distributed in zip-compressed files. To 015 * allow for the loading of an arbitrary number of these databases, 016 * one creates each StreetSegReader with a source directory argument, 017 * which will then be searched for Tiger Database files when 018 * <code>streetSegments()</code> is called. The subdirectories of the 019 * argument directory are not searched recursively for Tiger files as 020 * well; only the immediate contents of this.sourceDirectory will be 021 * considered as potential Tiger files. 022 * 023 * <p> StreetSegReader is only specified to operate correctly with 024 * directories that contain no <tt>.zip</tt> files besides the Tiger 025 * Databases. Files with other extensions (such as <tt>.pdf</tt>) 026 * will not affect the operation of StreetSegReader, but no other 027 * <tt>.zip</tt> files should be kept in the source directory for a 028 * StreetSegReader. 029 * 030 * @specfield sourceDirectory : String // name of directory where Tiger files are located 031 * @specfield streetSegs : Collection // contents of the database; each element is a StreetSegment 032 * 033 */ 034 public class StreetSegReader 035 { 036 037 private File sourceDirectory; 038 039 /** 040 * @effects Constructs a StreetSegReader where sourceDirectory 041 * contains the Tiger Database files. 042 * 043 * @throws InvalidSourceException if sourceDirectory is not valid 044 * database (most directories, even empty ones, count as valid). 045 **/ 046 public StreetSegReader(/*@Nullable*/ String sourceDirectory) 047 throws InvalidSourceException 048 { 049 try { 050 051 File source = null; 052 if (sourceDirectory != null) { 053 source = new File(sourceDirectory); 054 } 055 reader = new StreetSegReader(source); 056 057 } catch (StreetSegReader.InvalidSourceException e) { 058 throw new InvalidSourceException("" + e.getMessage()); 059 } 060 } 061 062 private StreetSegReader (/*@Nullable*/ File sourceDirFile) 063 throws InvalidSourceException { 064 065 if (sourceDirFile == null) { 066 throw new InvalidSourceException("DIRECTORY for StreetSegReader constructor cannot be null"); 067 } 068 069 if (!sourceDirFile.isDirectory()) { 070 throw new InvalidSourceException(sourceDirFile + " is not a valid DIRECTORY for StreetSegReader"); 071 } 072 073 // java.io.File is immutable 074 this.sourceDirectory = sourceDirFile; 075 } 076 077 // our adaptee 078 private StreetSegReader reader; 079 080 081 private static final FilenameFilter zipFileFilter = new ZipFilter(); 082 083 /** 084 * Filter class for only getting certain .zip files -- those that 085 * <b>match</b> the name. 086 */ 087 private static class ZipFilter 088 implements FilenameFilter { 089 public boolean accept(File d, String name) { 090 return (name.toLowerCase().endsWith("zip")); 091 } 092 } 093 094 095 /** 096 * Returns an Iterator over this.streetSegs. 097 * 098 * @throws Error if IO error while reading the directory 099 * @returns an iterator that produces the contents of 100 * this.streetSegs. Each element produced by the Iterator is a 101 * StreetSegment. 102 **/ 103 public Iterator<StreetSegment> iterator() { 104 return reader.streetSegmentsInternal(); 105 } 106 107 /** 108 * @throws Error if IO error while reading the directory 109 */ 110 protected StreetSegIterator streetSegmentsInternal() { 111 File[] filesToRead = sourceDirectory.listFiles(zipFileFilter); 112 if (filesToRead == null) { 113 // Some unknown I/O error ocurred while listing the files. 114 // This is rare and probably unrecoverable (sourceDirectory was 115 // already checked to be a directory). 116 // Not IOException so we don't have to declare it. 117 throw new Error("IO error while reading directory " + sourceDirectory); 118 } 119 StreetSegmentFilter killfilter = KillfileReader.fromDir(sourceDirectory); 120 return new StreetSegIterator(Arrays.asList(filesToRead).iterator(), killfilter); 121 } 122 123 /** 124 * Returns an Iterator over this.streetSegs. 125 * 126 * @modifies: System.err 127 * 128 * @effects: If (debug) then prints messages to System.err on 129 * progress of database reading. Else no change to System.err 130 * 131 * @throws Error if IO error while reading the directory 132 * 133 * @returns an iterator that produces the contents of 134 * this.streetSegs. Each element produced by the Iterator is a 135 * StreetSegment. 136 **/ 137 public Iterator<StreetSegment> streetSegments() { 138 StreetSegIterator iter = reader.streetSegmentsInternal(); 139 return iter; 140 } 141 142 // Inner classes 143 144 /** 145 * Exception indicating that the requested source for a 146 * tiger database is invalid 147 **/ 148 public static class InvalidSourceException 149 extends Exception { 150 public static final long serialVersionUID = 4534; 151 public InvalidSourceException(String msg) { super(msg); } 152 } 153 154 }