package org.osgi.service.indexer.impl; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.util.ArrayList; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.Manifest; import org.osgi.service.indexer.Resource; public class JarResource implements Resource { private final File file; private final JarFile jarFile; private final String location; private final Dictionary<String,Object> properties = new Hashtable<String,Object>(); private final Map<String,List<JarEntry>> prefixMap = new HashMap<String,List<JarEntry>>(); private final Map<String,JarEntry> paths = new HashMap<String,JarEntry>(); private Manifest manifest; public JarResource(File file) throws IOException { this.file = file; this.location = file.getPath().replace(File.separatorChar, '/'); this.jarFile = new JarFile(file); properties.put(NAME, file.getName()); properties.put(LOCATION, location); properties.put(SIZE, file.length()); properties.put(LAST_MODIFIED, file.lastModified()); Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String path = entry.getName(); paths.put(path, entry); String parentPath = getParentPath(path); List<JarEntry> list = getOrCreatePrefix(parentPath); list.add(entry); } } private static String getParentPath(String path) { int index; if (path.endsWith("/")) { index = path.substring(0, path.length() - 1).lastIndexOf("/"); } else { index = path.lastIndexOf("/"); } String parentPath; if (index == -1) parentPath = ""; else parentPath = path.substring(0, index + 1); return parentPath; } private synchronized List<JarEntry> getOrCreatePrefix(String prefix) { List<JarEntry> list = prefixMap.get(prefix); if (list == null) { list = new LinkedList<JarEntry>(); prefixMap.put(prefix, list); } return list; } public String getLocation() { return location; } public Dictionary<String,Object> getProperties() { return properties; } public long getSize() { return file.length(); } public InputStream getStream() throws IOException { return Files.newInputStream(file.toPath()); } public Manifest getManifest() throws IOException { synchronized (this) { if (manifest == null) { Resource manifestResource = getChild("META-INF/MANIFEST.MF"); if (manifestResource != null) { try (InputStream in = manifestResource.getStream()) { manifest = new Manifest(in); } finally { manifestResource.close(); } } } return manifest; } } public List<String> listChildren(String prefix) throws IOException { List<JarEntry> entries = prefixMap.get(prefix); if (entries == null) return null; List<String> result = new ArrayList<String>(entries.size()); for (JarEntry entry : entries) { String unprefixedPath = entry.getName().substring(prefix.length()); result.add(unprefixedPath); } return result; } public Resource getChild(String path) throws IOException { String childLocation = getLocation() + "#" + path; JarEntry entry = paths.get(path); if (entry == null) return null; return new FlatStreamResource(path, childLocation, jarFile.getInputStream(entry)); } public void close() { try { jarFile.close(); } catch (IOException e) { // Don't care } } }