package aQute.bnd.repository.maven.pom.provider; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import org.osgi.resource.Resource; import org.osgi.util.promise.Promise; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import aQute.bnd.http.HttpClient; import aQute.bnd.osgi.Processor; import aQute.bnd.osgi.repository.XMLResourceGenerator; import aQute.bnd.osgi.repository.XMLResourceParser; import aQute.maven.api.Archive; import aQute.maven.api.Revision; import aQute.maven.provider.MavenRepository; import aQute.service.reporter.Reporter; class SearchRepository extends InnerRepository { private final static Logger logger = LoggerFactory.getLogger(SearchRepository.class); final static long DEFAULT_MAX_STALE = TimeUnit.HOURS.toMillis(1); final String query; final String queryUrl; final Reporter reporter; final HttpClient client; final File cacheFile; SearchRepository(MavenRepository repo, File location, String query, String queryUrl, Reporter reporter, HttpClient client) throws Exception { super(repo, location); this.query = query; this.queryUrl = queryUrl; this.reporter = reporter; this.client = client; cacheFile = new File(location.getParentFile(), "pom-" + repo.getName() + ".query"); read(); } void refresh() throws Exception { SearchResult result = query(); Traverser traverser = new Traverser(getMavenRepository(), null, Processor.getExecutor()) .revisions(result.response.docsToRevisions()); Promise<Map<Archive,Resource>> p = traverser.getResources(); Collection<Resource> resources = p.getValue().values(); set(resources); save(getMavenRepository().getName(), resources, getLocation()); } void save(String name, Collection< ? extends Resource> resources, File location) throws Exception, IOException { XMLResourceGenerator generator = new XMLResourceGenerator(); generator.resources(resources); generator.name(name); generator.save(location); } void read() throws Exception { if (isStale()) { refresh(); } else { try (XMLResourceParser parser = new XMLResourceParser(getLocation())) { List<Resource> resources = parser.parse(); addAll(resources); } } } boolean isStale() { if (!getLocation().isFile()) return true; try { SearchResult result = query(); if (result.getLastModified() > getLocation().lastModified()) { return true; } } catch (Exception e) { // ignore } return false; } SearchResult query() throws Exception { URL url = new URL(queryUrl + '?' + query); int n = 0; while (true) { try { logger.debug("Searching {}", query); SearchResult result = client.build() .headers("User-Agent", "Bnd") .useCache(cacheFile, DEFAULT_MAX_STALE) .get(SearchResult.class) .go(url); logger.debug("Searched {}", result); return result; } catch (Exception e) { n++; if (n > 3) throw e; Thread.sleep(1000 * n); } } } public static class SearchResult { public SearchResult() throws Exception {}; public long getLastModified() { long timestamp = -1; for (Doc doc : Arrays.asList(response.docs)) if (doc.timestamp > timestamp) timestamp = doc.timestamp; return timestamp; } public ResponseHeader responseHeader; public Response response; } public static class ResponseHeader { public ResponseHeader() throws Exception {} public Map<String,String> params; /* * "responseHeader":{ "params":{ "spellcheck":"true", "fl": * "id,g,a,latestVersion,p,ec,repositoryId,text,timestamp,versionCount", * "sort":"score desc,timestamp desc,g asc,a asc", "indent":"off", * "q":"g:com.liferay", "spellcheck.count":"5", "wt":"json", "rows":"1", * "version":"2.2" } } */ } public static class Response { public Response() throws Exception {} public long numFound; public long start; public Doc[] docs; List<Revision> list; public List<Revision> docsToRevisions() { if (list != null) return list; List<Revision> newList = new ArrayList<>(); for (Doc doc : docs) newList.add(doc.toRevision()); return list = newList; } /* * "response":{ "numFound":648, "start":0, "docs":[ ... ] } */ } public static class Doc { public Doc() throws Exception {} public String id; public String g; public String a; public String v; public String latestVersion; public String repositoryId; public String p; public long timestamp; public int versionCount; public String[] ec; public String getVersion() { return (v != null) ? v : latestVersion; } public Revision toRevision() { return Revision.valueOf(toString()); } public String toString() { return String.format("%s:%s:%s", g, a, getVersion()); } /* * "id":"com.liferay:com.liferay.poshi.runner", "g":"com.liferay", * "a":"com.liferay.poshi.runner", "latestVersion":"1.0.44", * "repositoryId":"central", "p":"jar", "timestamp":1471476046000, * "versionCount":45, "ec":[ "-sources.jar", ".jar", ".pom" ] */ } }