package project; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.file.Path; import java.util.Arrays; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; import utils.lists.HashMap; import utils.lists.Map; import utils.lists.Paths; import utils.streams2.Stream; public class Plugin implements Comparable<Plugin> { public final Path root; public final HashMap<Path, byte[]> contents; public final HashMap<String, String> manifest; public final String id; public final String shape; public final String version; private final int version1; private final int version2; private final int version3; private final String version4; private Plugin(Path root, HashMap<Path, byte[]> contents, HashMap<String, String> manifest, String id, String shape, String version, int version1, int version2, int version3, String version4) { this.root = root; this.contents = contents.toHashMap(); this.manifest = manifest.toHashMap(); this.id = id; this.shape = shape; this.version = version; this.version1 = version1; this.version2 = version2; this.version3 = version3; this.version4 = version4; } private Plugin(Path path, HashMap<Path, byte[]> contents, HashMap<String, String> manifest) { this.shape = path.getFileName().toString().endsWith(".jar") ? ".jar" : ""; this.root = path; this.contents = contents; this.manifest = manifest; String[] split; if(manifest.containsKey("Bundle-Version")) { this.version = manifest.get("Bundle-Version"); split = Arrays.copyOfRange(version.split("\\.", 4), 0, 4); } else { this.version = "0.0.0"; split = new String[4]; } this.version1 = split[0] == null ? 0 : Integer.parseInt(split[0]); this.version2 = split[1] == null ? 0 : Integer.parseInt(split[1]); this.version3 = split[2] == null ? 0 : Integer.parseInt(split[2]); this.version4 = split[3] == null ? "" : split[3]; this.id = parseName(); } public Plugin(Path path, byte[] manifestBytes) throws IOException { this(path, new HashMap<>(), parseManifest(manifestBytes)); } public Plugin(Path path, HashMap<Path, byte[]> contents) throws IOException { this(path, contents, readManifest(path, contents)); } public String name() { return id; } public Plugin name(String name) { return new Plugin(root, contents, manifest, name, shape, version, version1, version2, version3, version4); } public Plugin manifest(HashMap<String, String> newManifest) { return new Plugin(root, contents, newManifest, id, shape, version, version1, version2, version3, version4); } public @Override int compareTo(Plugin o) { int n = id.compareTo(o.id); if(n != 0) return n; int v1 = version1 - o.version1; if(v1 != 0) return v1; int v2 = version2 - o.version2; if(v2 != 0) return v2; int v3 = version3 - o.version3; if(v3 != 0) return v3; return version4.compareTo(o.version4); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id.hashCode(); result = prime * result + version1; result = prime * result + version2; result = prime * result + version3; result = prime * result + version4.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; Plugin other = (Plugin) obj; if(!id.equals(other.id)) return false; if(version1 != other.version1) return false; if(version2 != other.version2) return false; if(version3 != other.version3) return false; if(!version4.equals(other.version4)) return false; return true; } @Override public String toString() { return "[" + id + "_" + version + shape + ", " + contents.size() + " files @ " + root + "]"; } public String fileName() { return bundleName() + "_" + version + shape; } public static HashMap<String, String> parseManifest(byte[] bytes) throws IOException { Attributes attr = new Manifest(new ByteArrayInputStream(bytes)).getMainAttributes(); Stream<Object> stream = Stream.from(attr.keySet()); return stream.toMap(o -> o.toString(), o -> attr.getValue((Attributes.Name) o)); } private String parseName() { String bundleName = bundleName(); if(version1 == 1 && "org.eclipse.jdt.annotation".equals(bundleName)) { return "org.eclipse.jdt.annotation_v1"; } return bundleName; } private String bundleName() { if(manifest.containsKey("Bundle-SymbolicName")) { return manifest.get("Bundle-SymbolicName").split(";")[0].trim(); } String fileName = root.getFileName().toString(); if(shape == "") { return fileName; } return fileName.substring(0, fileName.length() - shape.length()); } public Map<String, String> getLocalization(Snapshot snapshot) throws IOException { if(manifest.containsKey("Bundle-Localization")) { Path fileName = root.resolve(manifest.get("Bundle-Localization") + ".properties"); if(snapshot.isFound(fileName)) { return snapshot.getFileAsProperties(fileName); } } Path fileName = root.resolve("OSGI-INF/l10n/bundle.properties"); if(snapshot.isFound(fileName)) { return snapshot.getFileAsProperties(fileName); } return Map.of(); } private static HashMap<String, String> readManifest(Path path, HashMap<Path, byte[]> contents) throws IOException { byte[] manifestBytes = contents.get(Paths.get(JarFile.MANIFEST_NAME)); if(manifestBytes != null) { return parseManifest(manifestBytes); } return HashMap.of("Bundle-SymbolicName", path.getFileName().toString()); } }