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 26 package build.tools.module; 27 28 import javax.xml.namespace.QName; 29 import javax.xml.stream.XMLEventReader; 30 import javax.xml.stream.XMLInputFactory; 31 import javax.xml.stream.XMLStreamException; 32 import javax.xml.stream.events.Attribute; 33 import javax.xml.stream.events.XMLEvent; 34 import java.io.BufferedInputStream; 35 import java.io.IOException; 36 import java.io.InputStream; 37 import java.nio.file.Files; 38 import java.nio.file.Path; 39 import java.util.HashSet; 40 import java.util.Set; 41 42 public class ModulesXmlReader { 43 44 private ModulesXmlReader() {} 45 46 public static Set<Module> readModules(Path modulesXml) 47 throws XMLStreamException, IOException 48 { 49 Set<Module> modules = new HashSet<>(); 50 try (InputStream in = new BufferedInputStream(Files.newInputStream(modulesXml))) { 51 Set<Module> mods = ModulesXmlReader.load(in); 52 modules.addAll(mods); 53 } 54 return modules; 55 } 56 57 private static final String MODULES = "modules"; 58 private static final String MODULE = "module"; 59 private static final String NAME = "name"; 60 private static final String DEPEND = "depend"; 61 private static final String EXPORT = "export"; 62 private static final String TO = "to"; 63 private static final QName REEXPORTS = new QName("re-exports"); 64 private static Set<Module> load(InputStream in) 65 throws XMLStreamException, IOException 66 { 67 Set<Module> modules = new HashSet<>(); 68 XMLInputFactory factory = XMLInputFactory.newInstance(); 69 XMLEventReader stream = factory.createXMLEventReader(in); 70 Module.Builder mb = null; 71 String modulename = null; 72 String pkg = null; 73 Set<String> permits = new HashSet<>(); 74 while (stream.hasNext()) { 75 XMLEvent event = stream.nextEvent(); 76 if (event.isStartElement()) { 77 String startTag = event.asStartElement().getName().getLocalPart(); 78 switch (startTag) { 79 case MODULES: 80 break; 81 case MODULE: 82 if (mb != null) { 83 throw new RuntimeException("end tag for module is missing"); 84 } 85 modulename = getNextTag(stream, NAME); 86 mb = new Module.Builder(); 87 mb.name(modulename); 88 break; 89 case NAME: 90 throw new RuntimeException(event.toString()); 91 case DEPEND: 92 boolean reexports = false; 93 Attribute attr = event.asStartElement().getAttributeByName(REEXPORTS); 94 if (attr != null) { 95 String value = attr.getValue(); 96 if (value.equals("true") || value.equals("false")) { 97 reexports = Boolean.parseBoolean(value); 98 } else { 99 throw new RuntimeException("unexpected attribute " + attr.toString()); 100 } 101 } 102 mb.require(getData(stream), reexports); 103 break; 104 case EXPORT: 105 pkg = getNextTag(stream, NAME); 106 break; 107 case TO: 108 permits.add(getData(stream)); 109 break; 110 default: 111 } 112 } else if (event.isEndElement()) { 113 String endTag = event.asEndElement().getName().getLocalPart(); 114 switch (endTag) { 115 case MODULE: 116 modules.add(mb.build()); 117 mb = null; 118 break; 119 case EXPORT: 120 if (pkg == null) { 121 throw new RuntimeException("export-to is malformed"); 122 } 123 mb.exportTo(pkg, permits); 124 pkg = null; 125 permits.clear(); 126 break; 127 default: 128 } 129 } else if (event.isCharacters()) { 130 String s = event.asCharacters().getData(); 131 if (!s.trim().isEmpty()) { 132 throw new RuntimeException("export-to is malformed"); 133 } 134 } 135 } 136 return modules; 137 } 138 139 private static String getData(XMLEventReader reader) 140 throws XMLStreamException 141 { 142 XMLEvent e = reader.nextEvent(); 143 if (e.isCharacters()) 144 return e.asCharacters().getData(); 145 146 throw new RuntimeException(e.toString()); 147 } 148 149 private static String getNextTag(XMLEventReader reader, String tag) 150 throws XMLStreamException 151 { 152 XMLEvent e = reader.nextTag(); 153 if (e.isStartElement()) { 154 String t = e.asStartElement().getName().getLocalPart(); 155 if (!tag.equals(t)) { 156 throw new RuntimeException(e + " expected: " + tag); 157 } 158 return getData(reader); 159 } 160 throw new RuntimeException("export-to name is missing:" + e); 161 } 162 }