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.XMLOutputFactory; 30 import javax.xml.stream.XMLStreamException; 31 import javax.xml.stream.XMLStreamWriter; 32 import java.io.IOException; 33 import java.io.OutputStream; 34 import java.nio.file.Files; 35 import java.nio.file.Path; 36 import java.util.Collections; 37 import java.util.Comparator; 38 import java.util.Map; 39 import java.util.Set; 40 41 public final class ModulesXmlWriter { 42 43 private ModulesXmlWriter() {} 44 45 public static void writeModules(Set<Module> modules, Path path) 46 throws IOException, XMLStreamException 47 { 48 writeXML(modules, path); 49 } 50 51 private static final String MODULES = "modules"; 52 private static final String MODULE = "module"; 53 private static final String NAME = "name"; 54 private static final String DEPEND = "depend"; 55 private static final String EXPORT = "export"; 56 private static final String TO = "to"; 57 private static final QName REEXPORTS = new QName("re-exports"); 58 59 private static void writeXML(Set<Module> modules, Path path) 60 throws IOException, XMLStreamException 61 { 62 XMLOutputFactory xof = XMLOutputFactory.newInstance(); 63 try (OutputStream out = Files.newOutputStream(path)) { 64 int depth = 0; 65 XMLStreamWriter xtw = xof.createXMLStreamWriter(out, "UTF-8"); 66 xtw.writeStartDocument("utf-8","1.0"); 67 writeStartElement(xtw, MODULES, depth); 68 modules.stream() 69 .sorted(Comparator.comparing(Module::name)) 70 .forEach(m -> writeModuleElement(xtw, m, depth+1)); 71 writeEndElement(xtw, depth); 72 xtw.writeCharacters("\n"); 73 xtw.writeEndDocument(); 74 xtw.flush(); 75 xtw.close(); 76 } 77 } 78 79 private static void writeElement(XMLStreamWriter xtw, 80 String element, 81 String value, 82 int depth) { 83 try { 84 writeStartElement(xtw, element, depth); 85 xtw.writeCharacters(value); 86 xtw.writeEndElement(); 87 } catch (XMLStreamException e) { 88 throw new RuntimeException(e); 89 } 90 } 91 92 private static void writeDependElement(XMLStreamWriter xtw, 93 Module.Dependence d, 94 int depth) { 95 try { 96 writeStartElement(xtw, DEPEND, depth); 97 if (d.reexport) { 98 xtw.writeAttribute("re-exports", "true"); 99 } 100 xtw.writeCharacters(d.name); 101 xtw.writeEndElement(); 102 } catch (XMLStreamException e) { 103 throw new RuntimeException(e); 104 } 105 } 106 107 private static void writeExportElement(XMLStreamWriter xtw, 108 String pkg, 109 int depth) { 110 writeExportElement(xtw, pkg, Collections.emptySet(), depth); 111 } 112 113 private static void writeExportElement(XMLStreamWriter xtw, 114 String pkg, 115 Set<String> permits, 116 int depth) { 117 try { 118 writeStartElement(xtw, EXPORT, depth); 119 writeElement(xtw, NAME, pkg, depth+1); 120 if (!permits.isEmpty()) { 121 permits.stream().sorted() 122 .forEach(m -> writeElement(xtw, TO, m, depth + 1)); 123 } 124 writeEndElement(xtw, depth); 125 } catch (XMLStreamException e) { 126 throw new RuntimeException(e); 127 } 128 } 129 private static void writeModuleElement(XMLStreamWriter xtw, 130 Module m, 131 int depth) { 132 try { 133 writeStartElement(xtw, MODULE, depth); 134 writeElement(xtw, NAME, m.name(), depth+1); 135 m.requires().stream().sorted(Comparator.comparing(d -> d.name)) 136 .forEach(d -> writeDependElement(xtw, d, depth+1)); 137 m.exports().keySet().stream() 138 .filter(pn -> m.exports().get(pn).isEmpty()) 139 .sorted() 140 .forEach(pn -> writeExportElement(xtw, pn, depth+1)); 141 m.exports().entrySet().stream() 142 .filter(e -> !e.getValue().isEmpty()) 143 .sorted(Map.Entry.comparingByKey()) 144 .forEach(e -> writeExportElement(xtw, e.getKey(), e.getValue(), depth+1)); 145 writeEndElement(xtw, depth); 146 } catch (XMLStreamException e) { 147 throw new RuntimeException(e); 148 149 } 150 } 151 152 /** Two spaces; the default indentation. */ 153 public static final String DEFAULT_INDENT = " "; 154 155 /** stack[depth] indicates what's been written into the current scope. */ 156 private static String[] stack = new String[] { "\n", 157 "\n" + DEFAULT_INDENT, 158 "\n" + DEFAULT_INDENT + DEFAULT_INDENT, 159 "\n" + DEFAULT_INDENT + DEFAULT_INDENT + DEFAULT_INDENT}; 160 161 private static void writeStartElement(XMLStreamWriter xtw, 162 String name, 163 int depth) 164 throws XMLStreamException 165 { 166 xtw.writeCharacters(stack[depth]); 167 xtw.writeStartElement(name); 168 } 169 170 private static void writeEndElement(XMLStreamWriter xtw, int depth) 171 throws XMLStreamException 172 { 173 xtw.writeCharacters(stack[depth]); 174 xtw.writeEndElement(); 175 } 176 }