make/src/classes/build/tools/module/GenJdepsModulesXml.java
Print this page
@@ -23,33 +23,21 @@
* questions.
*/
package build.tools.module;
-import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
+import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
-import java.util.Objects;
import java.util.Set;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import javax.xml.namespace.QName;
-import javax.xml.stream.*;
-import javax.xml.stream.events.Attribute;
-import javax.xml.stream.events.XMLEvent;
+import java.util.stream.Collectors;
/**
* GenJdepsModulesXml augments the input modules.xml file(s)
* to include the module membership from the given path to
* the JDK exploded image. The output file is used by jdeps
@@ -95,391 +83,48 @@
GenJdepsModulesXml gentool = new GenJdepsModulesXml(modulepath);
Set<Module> modules = new HashSet<>();
for (; i < args.length; i++) {
Path p = Paths.get(args[i]);
- try (InputStream in = new BufferedInputStream(Files.newInputStream(p))) {
- Set<Module> mods = gentool.load(in);
- modules.addAll(mods);
- }
+ modules.addAll(ModulesXmlReader.readModules(p)
+ .stream()
+ .map(gentool::buildIncludes)
+ .collect(Collectors.toSet()));
}
Files.createDirectories(outfile.getParent());
- gentool.writeXML(modules, outfile);
+ ModulesXmlWriter.writeModules(modules, outfile);
}
final Path modulepath;
public GenJdepsModulesXml(Path modulepath) {
this.modulepath = modulepath;
}
- private static final String MODULES = "modules";
- private static final String MODULE = "module";
- private static final String NAME = "name";
- private static final String DEPEND = "depend";
- private static final String EXPORT = "export";
- private static final String TO = "to";
- private static final String INCLUDE = "include";
- private static final QName REEXPORTS = new QName("re-exports");
- private Set<Module> load(InputStream in) throws XMLStreamException, IOException {
- Set<Module> modules = new HashSet<>();
- XMLInputFactory factory = XMLInputFactory.newInstance();
- XMLEventReader stream = factory.createXMLEventReader(in);
- Module.Builder mb = null;
- String modulename = null;
- String pkg = null;
- Set<String> permits = new HashSet<>();
- while (stream.hasNext()) {
- XMLEvent event = stream.nextEvent();
- if (event.isStartElement()) {
- String startTag = event.asStartElement().getName().getLocalPart();
- switch (startTag) {
- case MODULES:
- break;
- case MODULE:
- if (mb != null) {
- throw new RuntimeException("end tag for module is missing");
- }
- modulename = getNextTag(stream, NAME);
- mb = new Module.Builder();
- mb.name(modulename);
- break;
- case NAME:
- throw new RuntimeException(event.toString());
- case DEPEND:
- boolean reexports = false;
- Attribute attr = event.asStartElement().getAttributeByName(REEXPORTS);
- if (attr != null) {
- String value = attr.getValue();
- if (value.equals("true") || value.equals("false")) {
- reexports = Boolean.parseBoolean(value);
- } else {
- throw new RuntimeException("unexpected attribute " + attr.toString());
- }
- }
- mb.require(getData(stream), reexports);
- break;
- case INCLUDE:
- throw new RuntimeException("unexpected " + event);
- case EXPORT:
- pkg = getNextTag(stream, NAME);
- break;
- case TO:
- permits.add(getData(stream));
- break;
- default:
- }
- } else if (event.isEndElement()) {
- String endTag = event.asEndElement().getName().getLocalPart();
- switch (endTag) {
- case MODULE:
- buildIncludes(mb, modulename);
- modules.add(mb.build());
- mb = null;
- break;
- case EXPORT:
- if (pkg == null) {
- throw new RuntimeException("export-to is malformed");
- }
- mb.exportTo(pkg, permits);
- pkg = null;
- permits.clear();
- break;
- default:
- }
- } else if (event.isCharacters()) {
- String s = event.asCharacters().getData();
- if (!s.trim().isEmpty()) {
- throw new RuntimeException("export-to is malformed");
- }
- }
- }
- return modules;
- }
-
- private String getData(XMLEventReader reader) throws XMLStreamException {
- XMLEvent e = reader.nextEvent();
- if (e.isCharacters()) {
- return e.asCharacters().getData();
- }
- throw new RuntimeException(e.toString());
- }
-
- private String getNextTag(XMLEventReader reader, String tag) throws XMLStreamException {
- XMLEvent e = reader.nextTag();
- if (e.isStartElement()) {
- String t = e.asStartElement().getName().getLocalPart();
- if (!tag.equals(t)) {
- throw new RuntimeException(e + " expected: " + tag);
- }
- return getData(reader);
- }
- throw new RuntimeException("export-to name is missing:" + e);
- }
- private void writeXML(Set<Module> modules, Path path)
- throws IOException, XMLStreamException
- {
- XMLOutputFactory xof = XMLOutputFactory.newInstance();
- try (OutputStream out = Files.newOutputStream(path)) {
- int depth = 0;
- XMLStreamWriter xtw = xof.createXMLStreamWriter(out, "UTF-8");
- xtw.writeStartDocument("utf-8","1.0");
- writeStartElement(xtw, MODULES, depth);
- modules.stream()
- .sorted(Comparator.comparing(Module::name))
- .forEach(m -> writeModuleElement(xtw, m, depth+1));
- writeEndElement(xtw, depth);
- xtw.writeCharacters("\n");
- xtw.writeEndDocument();
- xtw.flush();
- xtw.close();
- }
- }
-
- private void writeElement(XMLStreamWriter xtw, String element, String value, int depth) {
- try {
- writeStartElement(xtw, element, depth);
- xtw.writeCharacters(value);
- xtw.writeEndElement();
- } catch (XMLStreamException e) {
- throw new RuntimeException(e);
- }
- }
-
- private void writeDependElement(XMLStreamWriter xtw, Module.Dependence d, int depth) {
- try {
- writeStartElement(xtw, DEPEND, depth);
- if (d.reexport) {
- xtw.writeAttribute("re-exports", "true");
- }
- xtw.writeCharacters(d.name);
- xtw.writeEndElement();
- } catch (XMLStreamException e) {
- throw new RuntimeException(e);
- }
- }
-
- private void writeExportElement(XMLStreamWriter xtw, String pkg, int depth) {
- writeExportElement(xtw, pkg, Collections.emptySet(), depth);
- }
-
- private void writeExportElement(XMLStreamWriter xtw, String pkg,
- Set<String> permits, int depth) {
- try {
- writeStartElement(xtw, EXPORT, depth);
- writeElement(xtw, NAME, pkg, depth+1);
- if (!permits.isEmpty()) {
- permits.stream().sorted()
- .forEach(m -> writeElement(xtw, TO, m, depth + 1));
- }
- writeEndElement(xtw, depth);
- } catch (XMLStreamException e) {
- throw new RuntimeException(e);
- }
- }
- private void writeModuleElement(XMLStreamWriter xtw, Module m, int depth) {
- try {
- writeStartElement(xtw, MODULE, depth);
- writeElement(xtw, NAME, m.name(), depth+1);
- m.requires().stream().sorted(Comparator.comparing(d -> d.name))
- .forEach(d -> writeDependElement(xtw, d, depth+1));
- m.exports().keySet().stream()
- .filter(pn -> m.exports().get(pn).isEmpty())
- .sorted()
- .forEach(pn -> writeExportElement(xtw, pn, depth+1));
- m.exports().entrySet().stream()
- .filter(e -> !e.getValue().isEmpty())
- .sorted(Map.Entry.comparingByKey())
- .forEach(e -> writeExportElement(xtw, e.getKey(), e.getValue(), depth+1));
- m.packages().stream().sorted()
- .forEach(p -> writeElement(xtw, INCLUDE, p, depth+1));
- writeEndElement(xtw, depth);
- } catch (XMLStreamException e) {
- throw new RuntimeException(e);
-
- }
- }
-
- /** Two spaces; the default indentation. */
- public static final String DEFAULT_INDENT = " ";
-
- /** stack[depth] indicates what's been written into the current scope. */
- private static String[] stack = new String[] { "\n",
- "\n" + DEFAULT_INDENT,
- "\n" + DEFAULT_INDENT + DEFAULT_INDENT,
- "\n" + DEFAULT_INDENT + DEFAULT_INDENT + DEFAULT_INDENT};
-
- private void writeStartElement(XMLStreamWriter xtw, String name, int depth)
- throws XMLStreamException
- {
- xtw.writeCharacters(stack[depth]);
- xtw.writeStartElement(name);
- }
-
- private void writeEndElement(XMLStreamWriter xtw, int depth) throws XMLStreamException {
- xtw.writeCharacters(stack[depth]);
- xtw.writeEndElement();
- }
-
- private String packageName(Path p) {
+ private static String packageName(Path p) {
return packageName(p.toString().replace(File.separatorChar, '/'));
}
- private String packageName(String name) {
+ private static String packageName(String name) {
int i = name.lastIndexOf('/');
return (i > 0) ? name.substring(0, i).replace('/', '.') : "";
}
- private boolean includes(String name) {
- return name.endsWith(".class") && !name.equals("module-info.class");
+ private static boolean includes(String name) {
+ return name.endsWith(".class");
}
- public void buildIncludes(Module.Builder mb, String modulename) throws IOException {
- Path mclasses = modulepath.resolve(modulename);
+ public Module buildIncludes(Module module) {
+ Module.Builder mb = new Module.Builder(module);
+ Path mclasses = modulepath.resolve(module.name());
try {
Files.find(mclasses, Integer.MAX_VALUE, (Path p, BasicFileAttributes attr)
-> includes(p.getFileName().toString()))
.map(p -> packageName(mclasses.relativize(p)))
.forEach(mb::include);
} catch (NoSuchFileException e) {
// aggregate module may not have class
+ } catch (IOException ioe) {
+ throw new UncheckedIOException(ioe);
}
- }
-
- static class Module {
- static class Dependence {
- final String name;
- final boolean reexport;
- Dependence(String name) {
- this(name, false);
- }
- Dependence(String name, boolean reexport) {
- this.name = name;
- this.reexport = reexport;
- }
-
- @Override
- public int hashCode() {
- int hash = 5;
- hash = 11 * hash + Objects.hashCode(this.name);
- hash = 11 * hash + (this.reexport ? 1 : 0);
- return hash;
- }
-
- public boolean equals(Object o) {
- Dependence d = (Dependence)o;
- return this.name.equals(d.name) && this.reexport == d.reexport;
- }
- }
- private final String moduleName;
- private final Set<Dependence> requires;
- private final Map<String, Set<String>> exports;
- private final Set<String> packages;
-
- private Module(String name,
- Set<Dependence> requires,
- Map<String, Set<String>> exports,
- Set<String> packages) {
- this.moduleName = name;
- this.requires = Collections.unmodifiableSet(requires);
- this.exports = Collections.unmodifiableMap(exports);
- this.packages = Collections.unmodifiableSet(packages);
- }
-
- public String name() {
- return moduleName;
- }
-
- public Set<Dependence> requires() {
- return requires;
- }
-
- public Map<String, Set<String>> exports() {
- return exports;
- }
-
- public Set<String> packages() {
- return packages;
- }
-
- @Override
- public boolean equals(Object ob) {
- if (!(ob instanceof Module)) {
- return false;
- }
- Module that = (Module) ob;
- return (moduleName.equals(that.moduleName)
- && requires.equals(that.requires)
- && exports.equals(that.exports)
- && packages.equals(that.packages));
- }
-
- @Override
- public int hashCode() {
- int hc = moduleName.hashCode();
- hc = hc * 43 + requires.hashCode();
- hc = hc * 43 + exports.hashCode();
- hc = hc * 43 + packages.hashCode();
- return hc;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("module ").append(moduleName).append(" {").append("\n");
- requires.stream().sorted().forEach(d ->
- sb.append(String.format(" requires %s%s%n", d.reexport ? "public " : "", d.name)));
- exports.entrySet().stream().filter(e -> e.getValue().isEmpty())
- .sorted(Map.Entry.comparingByKey())
- .forEach(e -> sb.append(String.format(" exports %s%n", e.getKey())));
- exports.entrySet().stream().filter(e -> !e.getValue().isEmpty())
- .sorted(Map.Entry.comparingByKey())
- .forEach(e -> sb.append(String.format(" exports %s to %s%n", e.getKey(), e.getValue())));
- packages.stream().sorted().forEach(pn -> sb.append(String.format(" includes %s%n", pn)));
- sb.append("}");
- return sb.toString();
- }
-
- static class Builder {
- private String name;
- private final Set<Dependence> requires = new HashSet<>();
- private final Map<String, Set<String>> exports = new HashMap<>();
- private final Set<String> packages = new HashSet<>();
-
- public Builder() {
- }
-
- public Builder name(String n) {
- name = n;
- return this;
- }
-
- public Builder require(String d, boolean reexport) {
- requires.add(new Dependence(d, reexport));
- return this;
- }
-
- public Builder include(String p) {
- packages.add(p);
- return this;
- }
-
- public Builder export(String p) {
- return exportTo(p, Collections.emptySet());
- }
-
- public Builder exportTo(String p, Set<String> ms) {
- Objects.requireNonNull(p);
- Objects.requireNonNull(ms);
- if (exports.containsKey(p)) {
- throw new RuntimeException(name + " already exports " + p);
- }
- exports.put(p, new HashSet<>(ms));
- return this;
- }
-
- public Module build() {
- Module m = new Module(name, requires, exports, packages);
- return m;
- }
- }
+ return mb.build();
}
}