create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / file / iterator / DirectoryIterator.java
1 package net.sf.openrocket.file.iterator;
2
3 import java.io.BufferedInputStream;
4 import java.io.File;
5 import java.io.FileFilter;
6 import java.io.FileInputStream;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.net.URL;
10
11 import net.sf.openrocket.logging.LogHelper;
12 import net.sf.openrocket.startup.Application;
13 import net.sf.openrocket.util.JarUtil;
14 import net.sf.openrocket.util.Pair;
15
16 /**
17  * A DirectoryIterator that scans for files within a directory in the file system
18  * matching a FileFilter.  The scan is optionally recursive.
19  * 
20  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
21  */
22 public class DirectoryIterator extends FileIterator {
23         
24         private static final LogHelper logger = Application.getLogger();
25         
26         private final FileFilter filter;
27         private final File[] files;
28         private final boolean recursive;
29         private int position = 0;
30         private DirectoryIterator subIterator = null;
31         
32         /**
33          * Sole constructor.
34          * 
35          * @param directory             the directory to read.
36          * @param filter                the filter for selecting files.
37          * @throws IOException  if the directory cannot be read.
38          */
39         public DirectoryIterator(File directory, FileFilter filter, boolean recursive)
40                         throws IOException {
41                 
42                 this.filter = filter;
43                 this.recursive = recursive;
44                 
45                 this.files = directory.listFiles(new DirSelectionFileFilter(filter, recursive));
46                 if (this.files == null) {
47                         throw new IOException("not a directory or IOException occurred when listing files " +
48                                         "from " + directory);
49                 }
50         }
51         
52         
53
54
55
56         @Override
57         protected Pair<String, InputStream> findNext() {
58                 
59                 // Check if we're recursing
60                 if (subIterator != null) {
61                         if (subIterator.hasNext()) {
62                                 return subIterator.next();
63                         } else {
64                                 subIterator.close();
65                                 subIterator = null;
66                         }
67                 }
68                 
69                 // Scan through file entries
70                 while (position < files.length) {
71                         File file = files[position];
72                         position++;
73                         
74                         try {
75                                 if (recursive && file.isDirectory()) {
76                                         subIterator = new DirectoryIterator(file, filter, recursive);
77                                         if (subIterator.hasNext()) {
78                                                 return subIterator.next();
79                                         } else {
80                                                 subIterator.close();
81                                                 subIterator = null;
82                                                 continue;
83                                         }
84                                 }
85                                 
86                                 InputStream is = new BufferedInputStream(new FileInputStream(file));
87                                 return new Pair<String, InputStream>(file.getName(), is);
88                         } catch (IOException e) {
89                                 logger.warn("Error opening file/directory " + file, e);
90                         }
91                 }
92                 return null;
93         }
94         
95         
96
97         /**
98          * Return a DirectoryIterator for a directory that can be located either
99          * within the containing JAR file, in the classpath or in the current directory
100          * (searched in this order).  The first place that contains matching files
101          * will be iterated through.
102          * 
103          * @param directory             the directory to search for.
104          * @param filter                the filter for matching files in the directory.
105          * @return                              a DirectoryIterator for iterating through the files in the
106          *                                              directory, or <code>null</code> if no directory containing
107          *                                              matching files can be found.
108          */
109         public static FileIterator findDirectory(String directory, FileFilter filter) {
110                 FileIterator iterator = null;
111                 
112                 // Try to load from containing JAR file
113                 File jarFile = JarUtil.getCurrentJarFile();
114                 if (jarFile != null) {
115                         try {
116                                 iterator = new ZipDirectoryIterator(jarFile, directory, filter);
117                                 if (iterator.hasNext()) {
118                                         return iterator;
119                                 }
120                                 iterator.close();
121                         } catch (IOException e) {
122                                 logger.error("Error opening containing JAR file " + jarFile, e);
123                         }
124                 }
125                 
126
127                 // Try to find directory as a system resource
128                 URL url = ClassLoader.getSystemResource(directory);
129                 if (url != null) {
130                         try {
131                                 File dir = JarUtil.urlToFile(url);
132                                 iterator = new DirectoryIterator(dir, filter, true);
133                                 if (iterator.hasNext()) {
134                                         return iterator;
135                                 }
136                                 iterator.close();
137                         } catch (Exception e1) {
138                                 logger.error("Error opening directory from URL " + url);
139                         }
140                 }
141                 
142
143                 // Try to open directory as such
144                 try {
145                         iterator = new DirectoryIterator(new File(directory), filter, true);
146                         if (iterator.hasNext()) {
147                                 return iterator;
148                         }
149                         iterator.close();
150                 } catch (IOException e) {
151                         logger.error("Error opening directory " + directory);
152                 }
153                 
154                 return null;
155         }
156         
157         
158
159         /**
160          * A FileFilter wrapper that accepts or discards directories.
161          */
162         private class DirSelectionFileFilter implements FileFilter {
163                 
164                 private final boolean acceptDirs;
165                 private final FileFilter parentFilter;
166                 
167                 
168                 public DirSelectionFileFilter(FileFilter filter, boolean acceptDirs) {
169                         this.acceptDirs = acceptDirs;
170                         this.parentFilter = filter;
171                 }
172                 
173                 
174                 @Override
175                 public boolean accept(File pathname) {
176                         if (pathname.getName().startsWith(".")) {
177                                 return false;
178                         }
179                         if (pathname.isDirectory()) {
180                                 return acceptDirs;
181                         }
182                         return parentFilter.accept(pathname);
183                 }
184                 
185         }
186         
187 }