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