package project; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.file.Path; import java.util.Properties; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import utils.lists.ArrayList; import utils.lists.HashMap; import utils.lists.List; import utils.lists.Map; import utils.lists.Set; public class Feature implements Comparable<Feature> { public static class Plugin { public final String id; public final String os; public final String ws; public final String arch; public final String downloadSize; public final String installSize; public final String version; public final boolean fragment; public final boolean unpack; Plugin(XMLStreamReader reader, boolean fragmentByDefault) { this( fragmentByDefault, reader.getAttributeValue(null, "id"), reader.getAttributeValue(null, "os"), reader.getAttributeValue(null, "ws"), reader.getAttributeValue(null, "arch"), reader.getAttributeValue(null, "download-size"), reader.getAttributeValue(null, "install-size"), reader.getAttributeValue(null, "version"), reader.getAttributeValue(null, "fragment"), reader.getAttributeValue(null, "unpack")); } Plugin(boolean fragmentByDefault, String id, String os, String ws, String arch, String downloadSize, String installSize, String version, String fragment, String unpack) { this.id = id; this.os = os; this.ws = ws; this.arch = arch; this.downloadSize = downloadSize == null ? "0" : downloadSize; this.installSize = installSize == null ? "0" : installSize; this.version = version == null ? "0.0.0" : version; this.fragment = fragment == null ? fragmentByDefault : Boolean.parseBoolean(unpack); this.unpack = unpack == null ? true : Boolean.parseBoolean(unpack); } @Override public String toString() { return "[" + (id != null ? "id=" + id + ", " : "") + (os != null ? "os=" + os + ", " : "") + (ws != null ? "ws=" + ws + ", " : "") + (arch != null ? "arch=" + arch + ", " : "") + (downloadSize != null ? "downloadSize=" + downloadSize + ", " : "") + (installSize != null ? "installSize=" + installSize + ", " : "") + (version != null ? "version=" + version + ", " : "") + "fragment=" + fragment + ", unpack=" + unpack + "]"; } } public static class Import { public final String plugin; public final String feature; public final String version; public final String match; Import(XMLStreamReader reader) { this( reader.getAttributeValue(null, "feature"), reader.getAttributeValue(null, "plugin"), reader.getAttributeValue(null, "version"), reader.getAttributeValue(null, "match")); } Import(String feature, String plugin, String version, String match) { this.feature = feature; this.plugin = plugin; this.version = version == null ? "0.0.0" : version; this.match = match; } @Override public String toString() { return "[" + (plugin != null ? "plugin=" + plugin + ", " : "") + (feature != null ? "feature=" + feature + ", " : "") + (version != null ? "version=" + version + ", " : "") + (match != null ? "match=" + match : "") + "]"; } } public final Path path; public final String id; public final String plugin; public final String label; public final String version; public final String providerName; public final String licenseFeature; public final String licenseFeatureVersion; public final String descriptionURL; public final String description; public final String copyrightURL; public final String copyright; public final String licenseURL; public final String license; public final List<Import> requiresImports; public final List<Plugin> includes; public final List<Plugin> plugins; public final Map<String, String> properties; private static XMLInputFactory factory; public Feature(Path path, String id, String plugin, String label, String version, String providerName, String licenseFeature, String licenseFeatureVersion, String descriptionURL, String description, String copyrightURL, String copyright, String licenseURL, String license, ArrayList<Import> requiresImports, ArrayList<Plugin> includes, ArrayList<Plugin> plugins, HashMap<String, String> properties) { this.path = path; this.id = id; this.plugin = plugin; this.label = label; this.version = version; this.providerName = providerName; this.licenseFeature = licenseFeature; this.licenseFeatureVersion = licenseFeatureVersion; this.descriptionURL = descriptionURL; this.description = description; this.copyrightURL = copyrightURL; this.copyright = copyright; this.licenseURL = licenseURL; this.license = license; this.requiresImports = requiresImports.toList(); this.includes = includes.toList(); this.plugins = plugins.toList(); this.properties = properties == null ? Map.of() : properties.toMap(); } public static Feature fromXML(Path path, byte[] xmlBytes, byte[] propertiesBytes) throws XMLStreamException, IOException { if(factory == null) { factory = XMLInputFactory.newFactory(); } XMLStreamReader reader = factory.createXMLStreamReader(new ByteArrayInputStream(xmlBytes)); String featureID = null; String featurePlugin = null; String featureLabel = null; String featureVersion = null; String featureProviderName = null; String featureLicenseFeature = null; String featureLicenseFeatureVersion = null; String descriptionURL = null; String description = null; String copyrightURL = null; String copyright = null; String licenseURL = null; String license = null; ArrayList<Import> requiresImports = new ArrayList<>(); ArrayList<Plugin> includes = new ArrayList<>(); ArrayList<Plugin> plugins = new ArrayList<>(); HashMap<String, String> properties = readProperties(propertiesBytes); try { while(reader.hasNext()) { if(reader.next() == XMLStreamConstants.START_ELEMENT) { switch(reader.getLocalName()) { case "feature": featureID = reader.getAttributeValue(null, "id"); featurePlugin = reader.getAttributeValue(null, "plugin"); featureLabel = reader.getAttributeValue(null, "label"); featureVersion = reader.getAttributeValue(null, "version"); featureProviderName = reader.getAttributeValue(null, "provider-name"); featureLicenseFeature = reader.getAttributeValue(null, "license-feature"); featureLicenseFeatureVersion = reader.getAttributeValue(null, "license-feature-version"); break; case "description": descriptionURL = reader.getAttributeValue(null, "url"); description = reader.getElementText().trim(); break; case "copyright": copyrightURL = reader.getAttributeValue(null, "url"); copyright = reader.getElementText().trim(); break; case "license": licenseURL = reader.getAttributeValue(null, "url"); license = reader.getElementText().trim(); break; case "import": requiresImports.add(new Import(reader)); break; case "plugin": plugins.add(new Plugin(reader, false)); break; case "includes": includes.add(new Plugin(reader, true)); break; } } } } finally { reader.close(); } return new Feature( path, featureID, featurePlugin, featureLabel, featureVersion, featureProviderName, featureLicenseFeature, featureLicenseFeatureVersion, descriptionURL, description, copyrightURL, copyright, licenseURL, license, requiresImports, includes, plugins, properties); } public String mavenVersion() { return String.join(".", List.of(version.split("\\.")).subList(0, 3)) + "-SNAPSHOT"; } public String mavenGroupID() { if(id.startsWith("org.eclipse.equinox")) { return "org.eclipse.equinox"; } switch(id) { case "org.eclipse.rcp.configuration": return "org.eclipse.rcp.configuration"; } // case "org.eclipse.equinox.p2.extras.feature": // case "org.eclipse.equinox.p2.core.feature": // return "org.eclipse.equinox"; // case "org.eclipse.help": // return "org.eclipse.help.feature"; List<String> list = List.of(id.split("\\.")); return String.join(".", list.subList(0, Math.min(3, list.size()))) + ".feature"; } public String fileName() { return id + "_" + version; } private static HashMap<String, String> readProperties(byte[] bytes) throws IOException { if(bytes == null) { return HashMap.of(); } Properties props = new Properties(); props.load(new ByteArrayInputStream(bytes)); Set<String> names = Set.from(props.stringPropertyNames()); return names.stream().toMap(s -> s, s -> props.getProperty(s)); } public @Override int compareTo(Feature o) { return id.compareTo(o.id); } @Override public String toString() { return "[" + (id != null ? "id=" + id + ", " : "") + (plugin != null ? "plugin=" + plugin + ", " : "") + (label != null ? "label=" + label + ", " : "") + (version != null ? "version=" + version + ", " : "") + (providerName != null ? "providerName=" + providerName + ", " : "") + (licenseFeature != null ? "licenseFeature=" + licenseFeature + ", " : "") + (licenseFeatureVersion != null ? "licenseFeatureVersion=" + licenseFeatureVersion + ", " : "") + (descriptionURL != null ? "descriptionURL=" + descriptionURL + ", " : "") + (description != null ? "description=" + description + ", " : "") + (copyrightURL != null ? "copyrightURL=" + copyrightURL + ", " : "") + (copyright != null ? "copyright=" + copyright + ", " : "") + (licenseURL != null ? "licenseURL=" + licenseURL + ", " : "") + (license != null ? "license=" + license + ", " : "") + (requiresImports != null ? "requiresImports=" + requiresImports + ", " : "") + (includes != null ? "includes=" + includes + ", " : "") + (plugins != null ? "plugins=" + plugins + ", " : "") + (properties != null ? "properties=" + properties : "") + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((id == null) ? 0 : id.hashCode()); result = prime * result + ((version == null) ? 0 : version.hashCode()); return result; } @Override public boolean equals(Object obj) { if(this == obj) return true; if(obj == null) return false; if(getClass() != obj.getClass()) return false; Feature other = (Feature) obj; if(id == null) { if(other.id != null) return false; } else if(!id.equals(other.id)) return false; if(version == null) { if(other.version != null) return false; } else if(!version.equals(other.version)) return false; return true; } }