1 /* 2 * Copyright (c) 2012, 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 26 package org.openjdk.jigsaw; 27 28 import java.io.InputStream; 29 import java.util.Iterator; 30 import java.util.Map.Entry; 31 import org.openjdk.jigsaw.ModuleFile.ModuleFileHeader; 32 import org.openjdk.jigsaw.ModuleFile.SectionHeader; 33 import org.openjdk.jigsaw.ModuleFile.SubSectionFileHeader; 34 35 /** 36 * The ModuleFileParser interface supports parsing of a 37 * <a href="http://cr.openjdk.java.net/~mr/jigsaw/notes/module-file-format/"> 38 * <i>module file</i></a>. 39 * 40 * <p> The ModuleFileParser is designed to iterate over the module file using 41 * {@code hasNext()} and {@code next()}. The section type and data can be 42 * accessed using methods such as {@code getSectionHeader()}, 43 * {@code getContentStream()}, and {@code getClasses()}. </p> 44 * 45 * <p> The {@code next()} method causes the parser to read the next parse event, 46 * and returns an {@code Event} which identifies the type of event just read. 47 * The current event type can be determined invoking the {@code event()} 48 * method. </p> 49 * 50 * <p> Convenience methods, such as {@code skipToNextStartSection} and 51 * {@code skipToNextStartSubSection}, are defined to support easy access to 52 * (sub)section content without having to handle specific event types. </p> 53 * 54 * <p> A minimal example for using this API may look as follows: 55 * <pre> 56 * try (FileInputStream fis = new FileInputStream(jmodFile)) { 57 * ModuleFileParser parser = ModuleFile.newParser(fis); 58 * while (parser.skipToNextStartSection()) { 59 * SectionHeader header = parser.getSectionHeader(); 60 * SectionType type = header.getType(); 61 * switch (type) { 62 * case MODULE_INFO: 63 * out.format("%s section, %s%n", type, header); break; 64 * case SIGNATURE: 65 * out.format("%s section, %s%n", type, header); break; 66 * case CLASSES: 67 * out.format("%s section, %s%n", type, header); break; 68 * case RESOURCES: 69 * out.format("%s section, %s%n", type, header); break; 70 * case NATIVE_LIBS: 71 * out.format("%s section, %s%n", type, header); break; 72 * case NATIVE_CMDS: 73 * out.format("%s section, %s%n", type, header); break; 74 * case CONFIG: 75 * out.format("%s section, %s%n", type, header); break; 76 * default: 77 * throw new IOException("Unknown section type"); 78 * } 79 * } 80 * } 81 * </pre></p> 82 */ 83 84 public interface ModuleFileParser { 85 86 /** 87 * ModuleFileParser parsing events. 88 * 89 * <p> Events must follow the following grammar. 90 * <pre> 91 * START_FILE 92 * START_SECTION (MODULE_INFO must be present) 93 * END_SECTION 94 * [START_SECTION (optional sections) 95 * [START_SUBSECTION (sections with subsections) 96 * END_SUBSECTION]+ 97 * END_SECTION]+ 98 * END_FILE 99 * </pre> </p> 100 */ 101 public static enum Event { 102 /** 103 * The first event returned. The module header has been consumed. 104 */ 105 START_FILE, 106 /** 107 * The start of a section. The section header has been consumed. 108 */ 109 START_SECTION, 110 /** 111 * The start of a subsection. The subsection header has been consumed. 112 */ 113 START_SUBSECTION, 114 /** 115 * The end of a subsection. The subsection content has been consumed. 116 */ 117 END_SUBSECTION, 118 /** 119 * The end of a section. The section content has been consumed. 120 */ 121 END_SECTION, 122 /** 123 * The end of the module file. The file content has been consumed. 124 */ 125 END_FILE; 126 } 127 128 /** 129 * Returns the module file header. 130 * 131 * @return The module file header 132 */ 133 public ModuleFileHeader fileHeader(); 134 135 /** 136 * Returns current event of the parser. 137 */ 138 public Event event(); 139 140 /** 141 * Check if there are more events. 142 * 143 * @return true, if and only if, there are more events 144 */ 145 public boolean hasNext(); 146 147 /** 148 * Returns the next parsing event. 149 * 150 * <p> Skips over any unread data from a previous (sub)section. </p> 151 * 152 * @return the next parse event 153 * 154 * @throws NoSuchElementException 155 * If invoked when {@code hasNext} returns false 156 * 157 * @throws ModuleFileParserException 158 * If there is an error processing the underlying module file 159 */ 160 public Event next(); 161 162 /** 163 * Returns the header of the current section. 164 * 165 * @return the section header 166 * 167 * @throws ModuleFileParserException 168 * If the current event is one of START_FILE or END_FILE 169 */ 170 public SectionHeader getSectionHeader(); 171 172 /** 173 * Returns the header of the current file subsection. 174 * 175 * @return the subsection header 176 * 177 * @throws ModuleFileParserException 178 * If the current event is not one of START_SUBSECTION or END_SUBSECTION 179 */ 180 public SubSectionFileHeader getSubSectionFileHeader(); 181 182 /** 183 * Returns the hash of the module file header, current section, or file. 184 * 185 * <p> Returns the hash of the module file header if the current event is 186 * START_FILE, the section hash if the current event is END_SECTION, or the 187 * complete file contents hash if the current event is END_FILE. </p> 188 * 189 * <p> The specific hashes are calculated as per the module-file 190 * specification. More specifically, the module file header hash and the 191 * section hash exclude the follow fields from their header, the hash length 192 * and the hash value. The complete file contents hash excludes the file 193 * hash value in the module file header and the signature section 194 * (if present). </p> 195 * 196 * @return the hash bytes. 197 * 198 * @throws ModuleFileParserException 199 * If the current event is not one of START_FILE, END_SECTION, 200 * or END_FILE 201 */ 202 public byte[] getHash(); 203 204 /** 205 * Returns an InputStream of the uncompressed content of the current 206 * section or subsection (if the section defines a compressor), otherwise 207 * just the raw bytes. 208 * 209 * <p> For the CLASSES section ( {@code getSectionHeader.getType() == 210 * ModuleFile.SectionType.CLASSES} ) the {@code getClasses} method should be 211 * invoked. All other sections and subsections can invoke this method to get 212 * the uncompressed (sub)section content. </p> 213 * 214 * @return the content stream 215 * 216 * @throws ModuleFileParserException 217 * If the current event is not one of START_SECTION or 218 * START_SUBSECTION, if {@code getSectionHeader().getType()} returns 219 * {@code ModuleFile.SectionType.CLASSES}, or if there is an error 220 * processing the underlying module file 221 */ 222 public InputStream getContentStream(); 223 224 /** 225 * Returns an Iterator over the classes in the CLASSES section. 226 * 227 * <p> If this method is invoked to extract the content of the classes 228 * section then it must be invoked in a section whose 229 * {@code getSectionHeader.getType()} returns 230 * {@code ModuleFile.SectionType.CLASSES}. Any other time will throw a 231 * {@code ModuleFileParserException}. </p> 232 * 233 * @return an Iterator over the classes, where the entry key is the class 234 * file name, e.g. java/lang/Object.class, and the value is an 235 * input stream containing the class bytes. 236 * 237 * @throws ModuleFileParserException 238 * If the current event is not START_SECTION, if 239 * {@code getSectionHeader().getType()} does not return 240 * {@code ModuleFile.SectionType.CLASSES}, or if there is an error 241 * processing the underlying module file 242 */ 243 public Iterator<Entry<String,InputStream>> getClasses(); 244 245 /** 246 * Returns an InputStream of the raw bytes of the current section or 247 * subsection. 248 * 249 * <p> If the (sub)section data is compressed then this method simply 250 * returns the compressed bytes, and the invoker is responsible for 251 * decompressing. </p> 252 * 253 * @return The raw (sub)section data 254 * 255 * @throws ModuleFileParserException 256 * If the current event is not one of START_SECTION or START_SUBSECTION 257 */ 258 public InputStream getRawStream(); 259 260 /** 261 * Skips to the start of the next section. 262 * 263 * <p> Skips over any unread data, and consumes events until START_SECTION 264 * or END_FILE is encountered. </p> 265 * 266 * @return true, if and only if, the next event is START_SECTION 267 * 268 * @throws ModuleFileParserException 269 * If there is an error processing the underlying module file 270 */ 271 public boolean skipToNextStartSection(); 272 273 /** 274 * Skips to the start of the next subsection. 275 * 276 * <p> Skips over any unread data, and consumes events until END_SECTION 277 * is encountered. </p> 278 * 279 * @return true, if and only if, the current event is START_SUBSECTION 280 * 281 * @throws ModuleFileParserException 282 * If not within a section that contains subsections, or if there is 283 * an error processing the underlying module file 284 */ 285 public boolean skipToNextStartSubSection(); 286 }