1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.index.examples;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.FileNotFoundException;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.net.HttpURLConnection;
29 import java.net.URI;
30 import java.net.http.HttpClient;
31 import java.net.http.HttpRequest;
32 import java.net.http.HttpResponse;
33 import java.nio.file.Path;
34 import java.time.Duration;
35 import java.time.Instant;
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.Date;
39 import java.util.List;
40 import java.util.Map;
41
42 import org.apache.lucene.document.Document;
43 import org.apache.lucene.index.IndexReader;
44 import org.apache.lucene.index.MultiBits;
45 import org.apache.lucene.index.StoredFields;
46 import org.apache.lucene.search.BooleanClause.Occur;
47 import org.apache.lucene.search.BooleanQuery;
48 import org.apache.lucene.search.IndexSearcher;
49 import org.apache.lucene.search.Query;
50 import org.apache.lucene.util.Bits;
51 import org.apache.maven.index.ArtifactInfo;
52 import org.apache.maven.index.ArtifactInfoFilter;
53 import org.apache.maven.index.ArtifactInfoGroup;
54 import org.apache.maven.index.Field;
55 import org.apache.maven.index.FlatSearchRequest;
56 import org.apache.maven.index.FlatSearchResponse;
57 import org.apache.maven.index.GroupedSearchRequest;
58 import org.apache.maven.index.GroupedSearchResponse;
59 import org.apache.maven.index.Grouping;
60 import org.apache.maven.index.Indexer;
61 import org.apache.maven.index.IteratorSearchRequest;
62 import org.apache.maven.index.IteratorSearchResponse;
63 import org.apache.maven.index.MAVEN;
64 import org.apache.maven.index.context.IndexCreator;
65 import org.apache.maven.index.context.IndexUtils;
66 import org.apache.maven.index.context.IndexingContext;
67 import org.apache.maven.index.expr.SourcedSearchExpression;
68 import org.apache.maven.index.expr.UserInputSearchExpression;
69 import org.apache.maven.index.search.grouping.GAGrouping;
70 import org.apache.maven.index.updater.IndexUpdateRequest;
71 import org.apache.maven.index.updater.IndexUpdateResult;
72 import org.apache.maven.index.updater.IndexUpdater;
73 import org.apache.maven.index.updater.ResourceFetcher;
74 import org.codehaus.plexus.util.StringUtils;
75 import org.eclipse.aether.util.version.GenericVersionScheme;
76 import org.eclipse.aether.version.InvalidVersionSpecificationException;
77 import org.eclipse.aether.version.Version;
78
79 import static java.util.Objects.requireNonNull;
80
81
82
83
84 @Singleton
85 @Named
86 public class BasicUsageExample {
87 private final Indexer indexer;
88
89 private final IndexUpdater indexUpdater;
90
91 private final Map<String, IndexCreator> indexCreators;
92
93 private IndexingContext centralContext;
94
95 @Inject
96 public BasicUsageExample(Indexer indexer, IndexUpdater indexUpdater, Map<String, IndexCreator> indexCreators) {
97 this.indexer = requireNonNull(indexer);
98 this.indexUpdater = requireNonNull(indexUpdater);
99 this.indexCreators = requireNonNull(indexCreators);
100 }
101
102 public void perform() throws IOException, InvalidVersionSpecificationException {
103
104 Path centralLocalCache = Path.of("target/central-cache");
105 Path centralIndexDir = Path.of("target/central-index");
106
107
108 List<IndexCreator> indexers = new ArrayList<>();
109 indexers.add(requireNonNull(indexCreators.get("min")));
110 indexers.add(requireNonNull(indexCreators.get("jarContent")));
111 indexers.add(requireNonNull(indexCreators.get("maven-plugin")));
112
113
114 centralContext = indexer.createIndexingContext(
115 "central-context",
116 "central",
117 centralLocalCache.toFile(),
118 centralIndexDir.toFile(),
119 "https://repo1.maven.org/maven2",
120 null,
121 true,
122 true,
123 indexers);
124
125
126
127
128
129
130 if (true) {
131 Instant updateStart = Instant.now();
132 System.out.println("Updating Index...");
133 System.out.println("This might take a while on first run, so please be patient!");
134
135 Date centralContextCurrentTimestamp = centralContext.getTimestamp();
136 IndexUpdateRequest updateRequest = new IndexUpdateRequest(centralContext, new Java11HttpClient());
137 IndexUpdateResult updateResult = indexUpdater.fetchAndUpdateIndex(updateRequest);
138 if (updateResult.isFullUpdate()) {
139 System.out.println("Full update happened!");
140 } else if (updateResult.getTimestamp().equals(centralContextCurrentTimestamp)) {
141 System.out.println("No update needed, index is up to date!");
142 } else {
143 System.out.println("Incremental update happened, change covered " + centralContextCurrentTimestamp
144 + " - " + updateResult.getTimestamp() + " period.");
145 }
146
147 System.out.println("Finished in "
148 + Duration.between(updateStart, Instant.now()).getSeconds() + " sec");
149 System.out.println();
150 }
151
152 System.out.println();
153 System.out.println("Using index");
154 System.out.println("===========");
155 System.out.println();
156
157
158
159
160
161
162 if (false) {
163 final IndexSearcher searcher = centralContext.acquireIndexSearcher();
164 try {
165 final IndexReader ir = searcher.getIndexReader();
166 final StoredFields storedFields = ir.storedFields();
167 Bits liveDocs = MultiBits.getLiveDocs(ir);
168 for (int i = 0; i < ir.maxDoc(); i++) {
169 if (liveDocs == null || liveDocs.get(i)) {
170 final Document doc = storedFields.document(i);
171 final ArtifactInfo ai = IndexUtils.constructArtifactInfo(doc, centralContext);
172 if (ai != null) {
173 System.out.println(ai.getGroupId() + ":" + ai.getArtifactId() + ":" + ai.getVersion() + ":"
174 + ai.getClassifier() + " (sha1=" + ai.getSha1() + ")");
175 }
176 }
177 }
178 } finally {
179 centralContext.releaseIndexSearcher(searcher);
180 }
181 }
182
183
184
185
186
187 final GenericVersionScheme versionScheme = new GenericVersionScheme();
188 final String versionString = "3.1.0";
189 final Version version = versionScheme.parseVersion(versionString);
190
191
192 final Query groupIdQ = indexer.constructQuery(MAVEN.GROUP_ID, new SourcedSearchExpression("org.apache.maven"));
193 final Query artifactIdQ =
194 indexer.constructQuery(MAVEN.ARTIFACT_ID, new SourcedSearchExpression("maven-plugin-api"));
195
196 final BooleanQuery query = new BooleanQuery.Builder()
197 .add(groupIdQ, Occur.MUST)
198 .add(artifactIdQ, Occur.MUST)
199
200 .add(indexer.constructQuery(MAVEN.PACKAGING, new SourcedSearchExpression("jar")), Occur.MUST)
201
202
203 .add(
204 indexer.constructQuery(MAVEN.CLASSIFIER, new SourcedSearchExpression(Field.NOT_PRESENT)),
205 Occur.MUST_NOT)
206 .build();
207
208
209 final ArtifactInfoFilter versionFilter = (ctx, ai) -> {
210 try {
211 final Version aiV = versionScheme.parseVersion(ai.getVersion());
212
213 return aiV.compareTo(version) > 0;
214 } catch (InvalidVersionSpecificationException e) {
215
216 return true;
217 }
218 };
219
220 System.out.println("Searching for all GAVs with org.apache.maven:maven-plugin-api having V greater than 3.1.0");
221 final IteratorSearchRequest request =
222 new IteratorSearchRequest(query, Collections.singletonList(centralContext), versionFilter);
223 final IteratorSearchResponse response = indexer.searchIterator(request);
224 for (ArtifactInfo ai : response) {
225 System.out.println(ai.toString());
226 }
227
228
229
230
231 Query gidQ = indexer.constructQuery(MAVEN.GROUP_ID, new SourcedSearchExpression("org.apache.maven.indexer"));
232 Query aidQ = indexer.constructQuery(MAVEN.ARTIFACT_ID, new SourcedSearchExpression("indexer-core"));
233
234 BooleanQuery bq = new BooleanQuery.Builder()
235 .add(gidQ, Occur.MUST)
236 .add(aidQ, Occur.MUST)
237 .build();
238
239 searchAndDump(indexer, "all artifacts under GA org.apache.maven.indexer:indexer-core", bq);
240
241
242 bq = new BooleanQuery.Builder()
243 .add(gidQ, Occur.MUST)
244 .add(aidQ, Occur.MUST)
245 .add(indexer.constructQuery(MAVEN.CLASSIFIER, new SourcedSearchExpression("*")), Occur.MUST_NOT)
246 .build();
247
248 searchAndDump(indexer, "main artifacts under GA org.apache.maven.indexer:indexer-core", bq);
249
250
251 searchAndDump(
252 indexer,
253 "SHA1 7ab67e6b20e5332a7fb4fdf2f019aec4275846c2",
254 indexer.constructQuery(
255 MAVEN.SHA1, new SourcedSearchExpression("7ab67e6b20e5332a7fb4fdf2f019aec4275846c2")));
256
257 searchAndDump(
258 indexer,
259 "SHA1 7ab67e6b20 (partial hash)",
260 indexer.constructQuery(MAVEN.SHA1, new UserInputSearchExpression("7ab67e6b20")));
261
262
263 searchAndDump(
264 indexer,
265 "classname DefaultNexusIndexer (note: Central does not publish classes in the index)",
266 indexer.constructQuery(MAVEN.CLASSNAMES, new UserInputSearchExpression("DefaultNexusIndexer")));
267
268
269 bq = new BooleanQuery.Builder()
270 .add(indexer.constructQuery(MAVEN.PACKAGING, new SourcedSearchExpression("maven-plugin")), Occur.MUST)
271 .add(
272 indexer.constructQuery(MAVEN.GROUP_ID, new SourcedSearchExpression("org.apache.maven.plugins")),
273 Occur.MUST)
274 .build();
275
276 searchGroupedAndDumpFlat(indexer, "all \"canonical\" maven plugins", bq, new GAGrouping());
277
278
279 searchGroupedAndDump(
280 indexer,
281 "all maven archetypes (latest versions)",
282 indexer.constructQuery(MAVEN.PACKAGING, new SourcedSearchExpression("maven-archetype")),
283 new GAGrouping());
284
285
286 indexer.closeIndexingContext(centralContext, false);
287 }
288
289 public void searchAndDump(Indexer nexusIndexer, String descr, Query q) throws IOException {
290 System.out.println("Searching for " + descr);
291
292 FlatSearchResponse response = nexusIndexer.searchFlat(new FlatSearchRequest(q, centralContext));
293
294 for (ArtifactInfo ai : response.getResults()) {
295 System.out.println(ai.toString());
296 }
297
298 System.out.println("------");
299 System.out.println("Total: " + response.getTotalHitsCount());
300 System.out.println();
301 }
302
303 private static final int MAX_WIDTH = 60;
304
305 public void searchGroupedAndDumpFlat(Indexer nexusIndexer, String descr, Query q, Grouping g) throws IOException {
306 System.out.println("Searching for " + descr);
307
308 GroupedSearchResponse response = nexusIndexer.searchGrouped(new GroupedSearchRequest(q, g, centralContext));
309
310 for (Map.Entry<String, ArtifactInfoGroup> entry : response.getResults().entrySet()) {
311 ArtifactInfo ai = entry.getValue().getArtifactInfos().iterator().next();
312 System.out.println("* " + ai.getGroupId() + ":" + ai.getArtifactId() + ":" + ai.getVersion());
313 }
314
315 System.out.println("------");
316 System.out.println("Total record hits: " + response.getTotalHitsCount());
317 System.out.println();
318 }
319
320 public void searchGroupedAndDump(Indexer nexusIndexer, String descr, Query q, Grouping g) throws IOException {
321 System.out.println("Searching for " + descr);
322
323 GroupedSearchResponse response = nexusIndexer.searchGrouped(new GroupedSearchRequest(q, g, centralContext));
324
325 for (Map.Entry<String, ArtifactInfoGroup> entry : response.getResults().entrySet()) {
326 ArtifactInfo ai = entry.getValue().getArtifactInfos().iterator().next();
327 System.out.println("* Entry " + ai);
328 System.out.println(" Latest version: " + ai.getVersion());
329 System.out.println(
330 StringUtils.isBlank(ai.getDescription())
331 ? "No description in plugin's POM."
332 : StringUtils.abbreviate(ai.getDescription(), MAX_WIDTH));
333 System.out.println();
334 }
335
336 System.out.println("------");
337 System.out.println("Total record hits: " + response.getTotalHitsCount());
338 System.out.println();
339 }
340
341 private static class Java11HttpClient implements ResourceFetcher {
342 private final HttpClient client = HttpClient.newBuilder()
343 .followRedirects(HttpClient.Redirect.NEVER)
344 .build();
345
346 private URI uri;
347
348 @Override
349 public void connect(String id, String url) throws IOException {
350 this.uri = URI.create(url + "/");
351 }
352
353 @Override
354 public void disconnect() throws IOException {}
355
356 @Override
357 public InputStream retrieve(String name) throws IOException, FileNotFoundException {
358 HttpRequest request =
359 HttpRequest.newBuilder().uri(uri.resolve(name)).GET().build();
360 try {
361 HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
362 if (response.statusCode() == HttpURLConnection.HTTP_OK) {
363 return response.body();
364 } else {
365 throw new IOException("Unexpected response: " + response);
366 }
367 } catch (InterruptedException e) {
368 Thread.currentThread().interrupt();
369 throw new IOException(e);
370 }
371 }
372 }
373 }