28 import java.nio.file.ClosedDirectoryStreamException; |
28 import java.nio.file.ClosedDirectoryStreamException; |
29 import java.nio.file.DirectoryIteratorException; |
29 import java.nio.file.DirectoryIteratorException; |
30 import java.nio.file.NotDirectoryException; |
30 import java.nio.file.NotDirectoryException; |
31 import java.nio.file.Path; |
31 import java.nio.file.Path; |
32 import java.util.Iterator; |
32 import java.util.Iterator; |
|
33 import java.util.Objects; |
33 import java.util.NoSuchElementException; |
34 import java.util.NoSuchElementException; |
34 import java.io.IOException; |
35 import java.io.IOException; |
35 |
36 |
36 /** |
37 /** |
37 * DirectoryStream implementation for jrt file system implementations. |
38 * DirectoryStream implementation for jrt file system implementations. |
42 * but also compiled and delivered as part of the jrtfs.jar to support access |
43 * but also compiled and delivered as part of the jrtfs.jar to support access |
43 * to the jimage file provided by the shipped JDK by tools running on JDK 8. |
44 * to the jimage file provided by the shipped JDK by tools running on JDK 8. |
44 */ |
45 */ |
45 final class JrtDirectoryStream implements DirectoryStream<Path> { |
46 final class JrtDirectoryStream implements DirectoryStream<Path> { |
46 |
47 |
47 private final AbstractJrtFileSystem jrtfs; |
48 private final JrtPath dir; |
48 private final AbstractJrtPath dir; |
|
49 private final DirectoryStream.Filter<? super Path> filter; |
49 private final DirectoryStream.Filter<? super Path> filter; |
50 private volatile boolean isClosed; |
50 private volatile boolean isClosed; |
51 private volatile Iterator<Path> itr; |
51 private volatile Iterator<Path> itr; |
52 |
52 |
53 JrtDirectoryStream(AbstractJrtPath jrtPath, |
53 JrtDirectoryStream(JrtPath dir, |
54 DirectoryStream.Filter<? super java.nio.file.Path> filter) |
54 DirectoryStream.Filter<? super java.nio.file.Path> filter) |
55 throws IOException { |
55 throws IOException |
56 this.jrtfs = jrtPath.getFileSystem(); |
56 { |
57 this.dir = jrtPath; |
57 this.dir = dir; |
58 // sanity check |
58 if (!dir.jrtfs.isDirectory(dir, true)) { // sanity check |
59 if (!jrtfs.isDirectory(dir, true)) { |
59 throw new NotDirectoryException(dir.toString()); |
60 throw new NotDirectoryException(jrtPath.toString()); |
|
61 } |
60 } |
62 |
|
63 this.filter = filter; |
61 this.filter = filter; |
64 } |
62 } |
65 |
63 |
66 @Override |
64 @Override |
67 public synchronized Iterator<Path> iterator() { |
65 public synchronized Iterator<Path> iterator() { |
68 if (isClosed) { |
66 if (isClosed) |
69 throw new ClosedDirectoryStreamException(); |
67 throw new ClosedDirectoryStreamException(); |
70 } |
68 if (itr != null) |
71 if (itr != null) { |
|
72 throw new IllegalStateException("Iterator has already been returned"); |
69 throw new IllegalStateException("Iterator has already been returned"); |
73 } |
|
74 |
|
75 try { |
70 try { |
76 itr = jrtfs.iteratorOf(dir); |
71 itr = dir.jrtfs.iteratorOf(dir, filter); |
77 } catch (IOException e) { |
72 } catch (IOException e) { |
78 throw new IllegalStateException(e); |
73 throw new IllegalStateException(e); |
79 } |
74 } |
80 return new Iterator<Path>() { |
75 return new Iterator<Path>() { |
81 /* |
|
82 * next Path value to return from this iterator. |
|
83 * null value means hasNext() not called yet |
|
84 * or last hasNext() returned false or resulted |
|
85 * in exception. If last hasNext() returned true, |
|
86 * then this field has non-null value. |
|
87 */ |
|
88 private Path next; |
76 private Path next; |
89 |
|
90 // get-and-clear and set-next by these methods |
|
91 private Path getAndClearNext() { |
|
92 assert next != null; |
|
93 Path result = this.next; |
|
94 this.next = null; |
|
95 return result; |
|
96 } |
|
97 |
|
98 private void setNext(Path path) { |
|
99 assert path != null; |
|
100 this.next = path; |
|
101 } |
|
102 |
|
103 // if hasNext() returns true, 'next' field has non-null Path |
|
104 @Override |
77 @Override |
105 public synchronized boolean hasNext() { |
78 public synchronized boolean hasNext() { |
106 if (next != null) { |
79 if (isClosed) |
107 return true; |
|
108 } |
|
109 |
|
110 if (isClosed) { |
|
111 return false; |
80 return false; |
112 } |
81 return itr.hasNext(); |
113 |
|
114 if (filter == null) { |
|
115 if (itr.hasNext()) { |
|
116 setNext(itr.next()); |
|
117 return true; |
|
118 } else { |
|
119 return false; |
|
120 } |
|
121 } else { |
|
122 while (itr.hasNext()) { |
|
123 Path tmpPath = itr.next(); |
|
124 try { |
|
125 if (filter.accept(tmpPath)) { |
|
126 setNext(tmpPath); |
|
127 return true; |
|
128 } |
|
129 } catch (IOException ioe) { |
|
130 throw new DirectoryIteratorException(ioe); |
|
131 } |
|
132 } |
|
133 |
|
134 return false; |
|
135 } |
|
136 } |
82 } |
137 |
83 |
138 @Override |
84 @Override |
139 public synchronized Path next() { |
85 public synchronized Path next() { |
140 if (next != null) { |
86 if (isClosed) |
141 return getAndClearNext(); |
|
142 } |
|
143 |
|
144 if (isClosed) { |
|
145 throw new NoSuchElementException(); |
87 throw new NoSuchElementException(); |
146 } |
88 return itr.next(); |
147 |
|
148 if (next == null && itr.hasNext()) { |
|
149 // missing hasNext() between next() calls. |
|
150 if (hasNext()) { |
|
151 return getAndClearNext(); |
|
152 } |
|
153 } |
|
154 |
|
155 throw new NoSuchElementException(); |
|
156 } |
89 } |
157 |
90 |
158 @Override |
91 @Override |
159 public void remove() { |
92 public void remove() { |
160 throw new UnsupportedOperationException(); |
93 throw new UnsupportedOperationException(); |