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