package aQute.bnd.osgi.repository; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import org.osgi.resource.Capability; import org.osgi.resource.Requirement; import org.osgi.resource.Resource; import org.osgi.service.repository.Repository; import aQute.bnd.osgi.resource.CapabilityBuilder; import aQute.bnd.osgi.resource.ResourceBuilder; import aQute.bnd.osgi.resource.ResourceUtils; import aQute.bnd.osgi.resource.ResourceUtils.ContentCapability; import aQute.bnd.osgi.resource.ResourceUtils.IdentityCapability; import aQute.bnd.version.Version; import aQute.libg.glob.Glob; /** * Bridge an OSGi repository (requirements) and a bnd repository (bsn/version) * by creating an index and providing suitable methods. * <p> * This class ignores duplicate bsn/version entries */ public class BridgeRepository { private static final Requirement allRq = ResourceUtils.createWildcardRequirement(); private static final SortedSet<Version> EMPTY_VERSIONS = new TreeSet<>(); private final Repository repository; private final Map<String,Map<Version,ResourceInfo>> index = new HashMap<>(); public interface InfoCapability extends Capability { String error(); String name(); String from(); } static public class ResourceInfo { public ResourceInfo(Resource resource) { this.resource = resource; } boolean inited; Resource resource; boolean error; String tooltip; private String title; public String getTooltip() { init(); return tooltip; } private synchronized void init() { if ( inited ) return; inited = true; IdentityCapability ic = ResourceUtils.getIdentityCapability(resource); ContentCapability cc = ResourceUtils.getContentCapability(resource); String bsn = ic.osgi_identity(); Version version = ic.version(); InfoCapability info = getInfo(); String sha256 = cc == null ? "<>" : cc.osgi_content(); String error = null; String name = null; String from = null; if ( info != null) { error = info.error(); name = info.name(); from = info.from(); } if (error != null) { this.error = true; this.title = version + " [" + error + "]"; } else this.title = version.toString(); StringBuilder tsb = new StringBuilder(); if (this.error) tsb.append("ERROR: ").append(error).append("\n"); tsb.append(bsn).append("\n"); if ( ic.description(null) != null) { tsb.append(ic.description(null)); tsb.append("\n"); } tsb.append(bsn).append("\n"); tsb.append("Coordinates: ").append(name).append("\n"); tsb.append("SHA-256: ").append(sha256).append("\n"); if (from != null) { tsb.append("From: "); tsb.append(from); tsb.append("\n"); } this.tooltip = tsb.toString(); } public InfoCapability getInfo() { List<Capability> capabilities = resource.getCapabilities("bnd.info"); InfoCapability info; if (capabilities.size() >= 1) { info = ResourceUtils.as(capabilities.get(0), InfoCapability.class); } else info = null; return info; } public String getTitle() { init(); return title; } public boolean isError() { init(); return error; } } public BridgeRepository(Repository repository) throws Exception { this.repository = repository; index(); } private void index() throws Exception { Map<Requirement,Collection<Capability>> all = repository.findProviders(Collections.singleton(allRq)); for (Capability capability : all.get(allRq)) { Resource r = capability.getResource(); index(r); } } private void index(Resource r) throws Exception { IdentityCapability bc = ResourceUtils.getIdentityCapability(r); String bsn = bc.osgi_identity(); Version version = bc.version(); Map<Version,ResourceInfo> map = index.get(bsn); if (map == null) { map = new HashMap<>(); index.put(bsn, map); } map.put(version, new ResourceInfo(r)); } public Resource get(String bsn, Version version) throws Exception { ResourceInfo resourceInfo = getInfo(bsn, version); if (resourceInfo == null) return null; return resourceInfo.resource; } public ResourceInfo getInfo(String bsn, Version version) throws Exception { Map<Version,ResourceInfo> map = index.get(bsn); if (map == null) return null; return map.get(version); } public List<String> list(String pattern) throws Exception { List<String> bsns = new ArrayList<>(); if (pattern == null || pattern.equals("*") || pattern.equals("")) { bsns.addAll(index.keySet()); } else { String[] split = pattern.split("\\s+"); Glob globs[] = new Glob[split.length]; for (int i = 0; i < split.length; i++) { globs[i] = new Glob(split[i]); } outer: for (String bsn : index.keySet()) { for (Glob g : globs) { if (g.matcher(bsn).find()) { bsns.add(bsn); continue outer; } } } } return bsns; } public SortedSet<Version> versions(String bsn) throws Exception { Map<Version,ResourceInfo> map = index.get(bsn); if (map == null || map.isEmpty()) { return EMPTY_VERSIONS; } return new TreeSet<>(map.keySet()); } public Repository getRepository() { return repository; } public static void addInformationCapability(ResourceBuilder rb, String name, String from, Throwable error) { try { CapabilityBuilder c = new CapabilityBuilder("bnd.info"); c.addAttribute("name", name); if (from != null) c.addAttribute("from", from); if (error != null) c.addAttribute("error", error.toString()); rb.addCapability(c); } catch (Exception e) { e.printStackTrace(); } } public String tooltip(Object... target) throws Exception { if (target.length == 2) { ResourceInfo ri = getInfo((String) target[0], (Version) target[1]); return ri.getTooltip(); } return null; } public String title(Object... target) throws Exception { if (target.length == 2) { ResourceInfo ri = getInfo((String) target[0], (Version) target[1]); return ri.getTitle(); } if (target.length == 1) { String bsn = (String) target[0]; Map<Version,ResourceInfo> map = index.get(bsn); for (ResourceInfo ri : map.values()) { if (ri.isError()) return bsn + " [!]"; } return bsn; } return null; } }