1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package jdk.internal.jrtfs; 26 27 import java.nio.file.DirectoryStream; 28 import java.nio.file.ClosedDirectoryStreamException; 29 import java.nio.file.DirectoryIteratorException; 30 import java.nio.file.NotDirectoryException; 31 import java.nio.file.Path; 32 import java.util.Iterator; 33 import java.util.NoSuchElementException; 34 import java.io.IOException; 35 36 /** 37 * DirectoryStream implementation for jrt file system implementations. 38 * 39 * @implNote This class needs to maintain JDK 8 source compatibility. 40 * 41 * It is used internally in the JDK to implement jimage/jrtfs access, 42 * 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 */ 45 final class JrtDirectoryStream implements DirectoryStream<Path> { 46 47 private final AbstractJrtFileSystem jrtfs; 48 private final AbstractJrtPath dir; 49 private final DirectoryStream.Filter<? super Path> filter; 50 private volatile boolean isClosed; 51 private volatile Iterator<Path> itr; 52 53 JrtDirectoryStream(AbstractJrtPath jrtPath, 54 DirectoryStream.Filter<? super java.nio.file.Path> filter) 55 throws IOException { 56 this.jrtfs = jrtPath.getFileSystem(); 57 this.dir = jrtPath; 58 // sanity check 59 if (!jrtfs.isDirectory(dir, true)) { 60 throw new NotDirectoryException(jrtPath.toString()); 61 } 62 63 this.filter = filter; 64 } 65 66 @Override 67 public synchronized Iterator<Path> iterator() { 68 if (isClosed) { 69 throw new ClosedDirectoryStreamException(); 70 } 71 if (itr != null) { 72 throw new IllegalStateException("Iterator has already been returned"); 73 } 74 75 try { 76 itr = jrtfs.iteratorOf(dir); 77 } catch (IOException e) { 78 throw new IllegalStateException(e); 79 } 80 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; 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 105 public synchronized boolean hasNext() { 106 if (next != null) { 107 return true; 108 } 109 110 if (isClosed) { 111 return false; 112 } 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 } 137 138 @Override 139 public synchronized Path next() { 140 if (next != null) { 141 return getAndClearNext(); 142 } 143 144 if (isClosed) { 145 throw new NoSuchElementException(); 146 } 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 } 157 158 @Override 159 public void remove() { 160 throw new UnsupportedOperationException(); 161 } 162 }; 163 } 164 165 @Override 166 public synchronized void close() throws IOException { 167 isClosed = true; 168 } 169 }