package aQute.bnd.deployer.repository.wrapper; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import org.osgi.framework.FrameworkUtil; import org.osgi.resource.Capability; import org.osgi.resource.Requirement; import org.osgi.resource.Resource; import org.osgi.service.indexer.ResourceIndexer.IndexResult; import org.osgi.service.indexer.impl.KnownBundleAnalyzer; import org.osgi.service.indexer.impl.RepoIndex; import aQute.bnd.build.DownloadBlocker; import aQute.bnd.osgi.repository.BaseRepository; import aQute.bnd.osgi.resource.CapReqBuilder; import aQute.bnd.osgi.resource.PersistentResource; import aQute.bnd.osgi.resource.ResourceBuilder; import aQute.bnd.service.repository.InfoRepository; import aQute.bnd.service.repository.SearchableRepository.ResourceDescriptor; import aQute.bnd.version.Version; import aQute.lib.collections.MultiMap; import aQute.lib.filter.Filter; import aQute.lib.hex.Hex; import aQute.lib.persistentmap.PersistentMap; public class InfoRepositoryWrapper extends BaseRepository { final RepoIndex repoIndexer; final PersistentMap<PersistentResource> persistent; final Collection< ? extends InfoRepository> repos;; long lastTime = 0; private Properties augments = new Properties(); // private boolean inited; public InfoRepositoryWrapper(File dir, Collection< ? extends InfoRepository> repos) throws Exception { this.repoIndexer = new RepoIndex(); KnownBundleAnalyzer knownBundleAnalyzer = new KnownBundleAnalyzer(); this.augments = new Properties(); knownBundleAnalyzer.setKnownBundlesExtra(this.augments); this.repoIndexer.addAnalyzer(knownBundleAnalyzer, FrameworkUtil.createFilter("(name=*)")); this.repos = repos; this.persistent = new PersistentMap<PersistentResource>(dir, PersistentResource.class); } boolean init() { try { if (System.currentTimeMillis() < lastTime + 10000) return true; } finally { lastTime = System.currentTimeMillis(); } Set<String> errors = new LinkedHashSet<String>(); try { // // Get the current repo contents // Set<String> toBeDeleted = new HashSet<String>(persistent.keySet()); Map<String,DownloadBlocker> blockers = new HashMap<String,DownloadBlocker>(); for (InfoRepository repo : repos) { Map<String,ResourceDescriptor> map = collectKeys(repo); for (final Map.Entry<String,ResourceDescriptor> entry : map.entrySet()) { final String id = entry.getKey(); toBeDeleted.remove(id); if (persistent.containsKey(id)) continue; final ResourceDescriptor rd = entry.getValue(); DownloadBlocker blocker = new DownloadBlocker(null) { // // We steal the thread of the downloader to index // @Override public void success(File file) throws Exception { IndexResult index = null; try { index = repoIndexer.indexFile(file); ResourceBuilder rb = new ResourceBuilder(); // // Unfortunately, we need to convert the // caps/reqs // since they are not real caps/reqs // for (org.osgi.service.indexer.Capability capability : index.capabilities) { CapReqBuilder cb = new CapReqBuilder(capability.getNamespace()); cb.addAttributes(capability.getAttributes()); cb.addDirectives(capability.getDirectives()); rb.addCapability(cb.buildSyntheticCapability()); } for (org.osgi.service.indexer.Requirement requirement : index.requirements) { CapReqBuilder cb = new CapReqBuilder(requirement.getNamespace()); cb.addAttributes(requirement.getAttributes()); cb.addDirectives(requirement.getDirectives()); rb.addRequirement(cb.buildSyntheticRequirement()); } Resource resource = rb.build(); PersistentResource pr = new PersistentResource(resource); persistent.put(id, pr); } finally { super.success(file); if (index != null) { index.resource.close(); } } } }; blockers.put(entry.getKey(), blocker); repo.get(rd.bsn, rd.version, null, blocker); } } for (Entry<String,DownloadBlocker> entry : blockers.entrySet()) { String key = entry.getKey(); DownloadBlocker blocker = entry.getValue(); String reason = blocker.getReason(); if (reason != null) { errors.add(key + ": " + reason); } } persistent.keySet().removeAll(toBeDeleted); } catch (Exception e) { throw new RuntimeException(e); } if (!errors.isEmpty()) throw new IllegalStateException("Cannot index " + repos + " due to " + errors); return true; } /** * The repository method * * @throws Exception */ public void findProviders(Map<Requirement,List<Capability>> result, Collection< ? extends Requirement> requirements) throws Exception { init(); nextReq: for (Requirement req : requirements) { String f = req.getDirectives().get("filter"); if (f == null) continue nextReq; Filter filter = new Filter(f); for (PersistentResource presource : persistent.values()) { Resource resource = presource.getResource(); for (Capability cap : resource.getCapabilities(req.getNamespace())) { if (filter.matchMap(cap.getAttributes())) { List<Capability> l = result.get(req); if (l == null) result.put(req, l = new ArrayList<Capability>()); l.add(cap); } } } } } @SuppressWarnings({ "unchecked", "rawtypes" }) public Map<Requirement,Collection<Capability>> findProviders(Collection< ? extends Requirement> requirements) { MultiMap<Requirement,Capability> result = new MultiMap<Requirement,Capability>(); try { findProviders(result, requirements); return (Map) result; } catch (Exception e) { throw new RuntimeException(e); } } /* * Get all the shas from the repo */ private Map<String,ResourceDescriptor> collectKeys(InfoRepository repo) throws Exception { Map<String,ResourceDescriptor> map = new HashMap<String,ResourceDescriptor>(); for (String bsn : repo.list(null)) { for (Version version : repo.versions(bsn)) { ResourceDescriptor rd = repo.getDescriptor(bsn, version); if (rd != null) map.put(Hex.toHexString(rd.id), rd); } } return map; } public String toString() { return "InfoRepositoryWrapper[" + repos.size() + "]"; } public void close() throws IOException { persistent.close(); } public void addAugment(Properties properties) { augments.putAll(properties); } public void clear() { this.persistent.clear(); } /** * Clear all files that were indexed before this date * * @param whenOlder */ public void clear(long whenOlder) { persistent.clear(whenOlder); } }