View Javadoc
1   package org.apache.maven.indexer.examples;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.lucene.document.Document;
23  import org.apache.lucene.index.IndexReader;
24  import org.apache.lucene.index.MultiFields;
25  import org.apache.lucene.search.BooleanClause.Occur;
26  import org.apache.lucene.search.BooleanQuery;
27  import org.apache.lucene.search.IndexSearcher;
28  import org.apache.lucene.search.Query;
29  import org.apache.lucene.util.Bits;
30  import org.apache.maven.index.ArtifactInfo;
31  import org.apache.maven.index.ArtifactInfoFilter;
32  import org.apache.maven.index.ArtifactInfoGroup;
33  import org.apache.maven.index.Field;
34  import org.apache.maven.index.FlatSearchRequest;
35  import org.apache.maven.index.FlatSearchResponse;
36  import org.apache.maven.index.GroupedSearchRequest;
37  import org.apache.maven.index.GroupedSearchResponse;
38  import org.apache.maven.index.Grouping;
39  import org.apache.maven.index.Indexer;
40  import org.apache.maven.index.IteratorSearchRequest;
41  import org.apache.maven.index.IteratorSearchResponse;
42  import org.apache.maven.index.MAVEN;
43  import org.apache.maven.index.context.IndexCreator;
44  import org.apache.maven.index.context.IndexUtils;
45  import org.apache.maven.index.context.IndexingContext;
46  import org.apache.maven.index.expr.SourcedSearchExpression;
47  import org.apache.maven.index.expr.UserInputSearchExpression;
48  import org.apache.maven.index.search.grouping.GAGrouping;
49  import org.apache.maven.index.updater.IndexUpdateRequest;
50  import org.apache.maven.index.updater.IndexUpdateResult;
51  import org.apache.maven.index.updater.IndexUpdater;
52  import org.apache.maven.index.updater.ResourceFetcher;
53  import org.apache.maven.index.updater.WagonHelper;
54  import org.apache.maven.wagon.Wagon;
55  import org.apache.maven.wagon.events.TransferEvent;
56  import org.apache.maven.wagon.events.TransferListener;
57  import org.apache.maven.wagon.observers.AbstractTransferListener;
58  import org.codehaus.plexus.DefaultContainerConfiguration;
59  import org.codehaus.plexus.DefaultPlexusContainer;
60  import org.codehaus.plexus.PlexusConstants;
61  import org.codehaus.plexus.PlexusContainer;
62  import org.codehaus.plexus.PlexusContainerException;
63  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
64  import org.codehaus.plexus.util.StringUtils;
65  import org.eclipse.aether.util.version.GenericVersionScheme;
66  import org.eclipse.aether.version.InvalidVersionSpecificationException;
67  import org.eclipse.aether.version.Version;
68  
69  import java.io.File;
70  import java.io.IOException;
71  import java.util.ArrayList;
72  import java.util.Collections;
73  import java.util.Date;
74  import java.util.List;
75  import java.util.Map;
76  
77  /**
78   * Collection of some use cases.
79   */
80  public class BasicUsageExample
81  {
82      public static void main( String[] args )
83          throws Exception
84      {
85          final BasicUsageExample basicUsageExample = new BasicUsageExample();
86          basicUsageExample.perform();
87      }
88  
89      // ==
90  
91      private final PlexusContainer plexusContainer;
92  
93      private final Indexer indexer;
94  
95      private final IndexUpdater indexUpdater;
96  
97      private final Wagon httpWagon;
98  
99      private IndexingContext centralContext;
100 
101     public BasicUsageExample()
102         throws PlexusContainerException, ComponentLookupException
103     {
104         // here we create Plexus container, the Maven default IoC container
105         // Plexus falls outside of MI scope, just accept the fact that
106         // MI is a Plexus component ;)
107         // If needed more info, ask on Maven Users list or Plexus Users list
108         // google is your friend!
109         final DefaultContainerConfiguration config = new DefaultContainerConfiguration();
110         config.setClassPathScanning( PlexusConstants.SCANNING_INDEX );
111         this.plexusContainer = new DefaultPlexusContainer( config );
112 
113         // lookup the indexer components from plexus
114         this.indexer = plexusContainer.lookup( Indexer.class );
115         this.indexUpdater = plexusContainer.lookup( IndexUpdater.class );
116         // lookup wagon used to remotely fetch index
117         this.httpWagon = plexusContainer.lookup( Wagon.class, "http" );
118 
119     }
120 
121     public void perform()
122         throws IOException, ComponentLookupException, InvalidVersionSpecificationException
123     {
124         // Files where local cache is (if any) and Lucene Index should be located
125         File centralLocalCache = new File( "target/central-cache" );
126         File centralIndexDir = new File( "target/central-index" );
127 
128         // Creators we want to use (search for fields it defines)
129         List<IndexCreator> indexers = new ArrayList<>();
130         indexers.add( plexusContainer.lookup( IndexCreator.class, "min" ) );
131         indexers.add( plexusContainer.lookup( IndexCreator.class, "jarContent" ) );
132         indexers.add( plexusContainer.lookup( IndexCreator.class, "maven-plugin" ) );
133 
134         // Create context for central repository index
135         centralContext =
136             indexer.createIndexingContext( "central-context", "central", centralLocalCache, centralIndexDir,
137                                            "http://repo1.maven.org/maven2", null, true, true, indexers );
138 
139         // Update the index (incremental update will happen if this is not 1st run and files are not deleted)
140         // This whole block below should not be executed on every app start, but rather controlled by some configuration
141         // since this block will always emit at least one HTTP GET. Central indexes are updated once a week, but
142         // other index sources might have different index publishing frequency.
143         // Preferred frequency is once a week.
144         if ( true )
145         {
146             System.out.println( "Updating Index..." );
147             System.out.println( "This might take a while on first run, so please be patient!" );
148             // Create ResourceFetcher implementation to be used with IndexUpdateRequest
149             // Here, we use Wagon based one as shorthand, but all we need is a ResourceFetcher implementation
150             TransferListener listener = new AbstractTransferListener()
151             {
152                 public void transferStarted( TransferEvent transferEvent )
153                 {
154                     System.out.print( "  Downloading " + transferEvent.getResource().getName() );
155                 }
156 
157                 public void transferProgress( TransferEvent transferEvent, byte[] buffer, int length )
158                 {
159                 }
160 
161                 public void transferCompleted( TransferEvent transferEvent )
162                 {
163                     System.out.println( " - Done" );
164                 }
165             };
166             ResourceFetcher resourceFetcher = new WagonHelper.WagonFetcher( httpWagon, listener, null, null );
167 
168             Date centralContextCurrentTimestamp = centralContext.getTimestamp();
169             IndexUpdateRequest updateRequest = new IndexUpdateRequest( centralContext, resourceFetcher );
170             IndexUpdateResult updateResult = indexUpdater.fetchAndUpdateIndex( updateRequest );
171             if ( updateResult.isFullUpdate() )
172             {
173                 System.out.println( "Full update happened!" );
174             }
175             else if ( updateResult.getTimestamp().equals( centralContextCurrentTimestamp ) )
176             {
177                 System.out.println( "No update needed, index is up to date!" );
178             }
179             else
180             {
181                 System.out.println(
182                     "Incremental update happened, change covered " + centralContextCurrentTimestamp + " - "
183                         + updateResult.getTimestamp() + " period." );
184             }
185 
186             System.out.println();
187         }
188 
189         System.out.println();
190         System.out.println( "Using index" );
191         System.out.println( "===========" );
192         System.out.println();
193 
194         // ====
195         // Case:
196         // dump all the GAVs
197         // NOTE: will not actually execute do this below, is too long to do (Central is HUGE), but is here as code
198         // example
199         if ( false )
200         {
201             final IndexSearcher searcher = centralContext.acquireIndexSearcher();
202             try
203             {
204                 final IndexReader ir = searcher.getIndexReader();
205                 Bits liveDocs = MultiFields.getLiveDocs( ir );
206                 for ( int i = 0; i < ir.maxDoc(); i++ )
207                 {
208                     if ( liveDocs == null || liveDocs.get( i ) )
209                     {
210                         final Document doc = ir.document( i );
211                         final ArtifactInfo ai = IndexUtils.constructArtifactInfo( doc, centralContext );
212                         System.out.println( ai.getGroupId() + ":" + ai.getArtifactId() + ":" + ai.getVersion() + ":"
213                                                 + ai.getClassifier() + " (sha1=" + ai.getSha1() + ")" );
214                     }
215                 }
216             }
217             finally
218             {
219                 centralContext.releaseIndexSearcher( searcher );
220             }
221         }
222 
223         // ====
224         // Case:
225         // Search for all GAVs with known G and A and having version greater than V
226 
227         final GenericVersionScheme versionScheme = new GenericVersionScheme();
228         final String versionString = "1.5.0";
229         final Version version = versionScheme.parseVersion( versionString );
230 
231         // construct the query for known GA
232         final Query groupIdQ =
233             indexer.constructQuery( MAVEN.GROUP_ID, new SourcedSearchExpression( "org.sonatype.nexus" ) );
234         final Query artifactIdQ =
235             indexer.constructQuery( MAVEN.ARTIFACT_ID, new SourcedSearchExpression( "nexus-api" ) );
236         final BooleanQuery query = new BooleanQuery();
237         query.add( groupIdQ, Occur.MUST );
238         query.add( artifactIdQ, Occur.MUST );
239 
240         // we want "jar" artifacts only
241         query.add( indexer.constructQuery( MAVEN.PACKAGING, new SourcedSearchExpression( "jar" ) ), Occur.MUST );
242         // we want main artifacts only (no classifier)
243         // Note: this below is unfinished API, needs fixing
244         query.add( indexer.constructQuery( MAVEN.CLASSIFIER, new SourcedSearchExpression( Field.NOT_PRESENT ) ),
245                    Occur.MUST_NOT );
246 
247         // construct the filter to express "V greater than"
248         final ArtifactInfoFilter versionFilter = new ArtifactInfoFilter()
249         {
250             public boolean accepts( final IndexingContext ctx, final ArtifactInfo ai )
251             {
252                 try
253                 {
254                     final Version aiV = versionScheme.parseVersion( ai.getVersion() );
255                     // Use ">=" if you are INCLUSIVE
256                     return aiV.compareTo( version ) > 0;
257                 }
258                 catch ( InvalidVersionSpecificationException e )
259                 {
260                     // do something here? be safe and include?
261                     return true;
262                 }
263             }
264         };
265 
266         System.out.println(
267             "Searching for all GAVs with G=org.sonatype.nexus and nexus-api and having V greater than 1.5.0" );
268         final IteratorSearchRequest request =
269             new IteratorSearchRequest( query, Collections.singletonList( centralContext ), versionFilter );
270         final IteratorSearchResponse response = indexer.searchIterator( request );
271         for ( ArtifactInfo ai : response )
272         {
273             System.out.println( ai.toString() );
274         }
275 
276         // Case:
277         // Use index
278         // Searching for some artifact
279         Query gidQ =
280             indexer.constructQuery( MAVEN.GROUP_ID, new SourcedSearchExpression( "org.apache.maven.indexer" ) );
281         Query aidQ = indexer.constructQuery( MAVEN.ARTIFACT_ID, new SourcedSearchExpression( "indexer-artifact" ) );
282 
283         BooleanQuery bq = new BooleanQuery();
284         bq.add( gidQ, Occur.MUST );
285         bq.add( aidQ, Occur.MUST );
286 
287         searchAndDump( indexer, "all artifacts under GA org.apache.maven.indexer:indexer-artifact", bq );
288 
289         // Searching for some main artifact
290         bq = new BooleanQuery();
291         bq.add( gidQ, Occur.MUST );
292         bq.add( aidQ, Occur.MUST );
293         // bq.add( nexusIndexer.constructQuery( MAVEN.CLASSIFIER, new SourcedSearchExpression( "*" ) ), Occur.MUST_NOT
294         // );
295 
296         searchAndDump( indexer, "main artifacts under GA org.apache.maven.indexer:indexer-artifact", bq );
297 
298         // doing sha1 search
299         searchAndDump( indexer, "SHA1 7ab67e6b20e5332a7fb4fdf2f019aec4275846c2",
300                        indexer.constructQuery( MAVEN.SHA1,
301                                                new SourcedSearchExpression( "7ab67e6b20e5332a7fb4fdf2f019aec4275846c2" )
302                        )
303         );
304 
305         searchAndDump( indexer, "SHA1 7ab67e6b20 (partial hash)",
306                        indexer.constructQuery( MAVEN.SHA1, new UserInputSearchExpression( "7ab67e6b20" ) ) );
307 
308         // doing classname search (incomplete classname)
309         searchAndDump( indexer, "classname DefaultNexusIndexer (note: Central does not publish classes in the index)",
310                        indexer.constructQuery( MAVEN.CLASSNAMES,
311                                                new UserInputSearchExpression( "DefaultNexusIndexer" ) ) );
312 
313         // doing search for all "canonical" maven plugins latest versions
314         bq = new BooleanQuery();
315         bq.add( indexer.constructQuery( MAVEN.PACKAGING, new SourcedSearchExpression( "maven-plugin" ) ), Occur.MUST );
316         bq.add( indexer.constructQuery( MAVEN.GROUP_ID, new SourcedSearchExpression( "org.apache.maven.plugins" ) ),
317                 Occur.MUST );
318         searchGroupedAndDump( indexer, "all \"canonical\" maven plugins", bq, new GAGrouping() );
319 
320         // doing search for all archetypes latest versions
321         searchGroupedAndDump( indexer, "all maven archetypes (latest versions)",
322                               indexer.constructQuery( MAVEN.PACKAGING,
323                                                       new SourcedSearchExpression( "maven-archetype" ) ),
324                               new GAGrouping() );
325 
326         // close cleanly
327         indexer.closeIndexingContext( centralContext, false );
328     }
329 
330     public void searchAndDump( Indexer nexusIndexer, String descr, Query q )
331         throws IOException
332     {
333         System.out.println( "Searching for " + descr );
334 
335         FlatSearchResponse response = nexusIndexer.searchFlat( new FlatSearchRequest( q, centralContext ) );
336 
337         for ( ArtifactInfo ai : response.getResults() )
338         {
339             System.out.println( ai.toString() );
340         }
341 
342         System.out.println( "------" );
343         System.out.println( "Total: " + response.getTotalHitsCount() );
344         System.out.println();
345     }
346 
347     private static final int MAX_WIDTH = 60;
348 
349     public void searchGroupedAndDump( Indexer nexusIndexer, String descr, Query q, Grouping g )
350         throws IOException
351     {
352         System.out.println( "Searching for " + descr );
353 
354         GroupedSearchResponse response = nexusIndexer.searchGrouped( new GroupedSearchRequest( q, g, centralContext ) );
355 
356         for ( Map.Entry<String, ArtifactInfoGroup> entry : response.getResults().entrySet() )
357         {
358             ArtifactInfo ai = entry.getValue().getArtifactInfos().iterator().next();
359             System.out.println( "* Entry " + ai );
360             System.out.println( "  Latest version:  " + ai.getVersion() );
361             System.out.println( StringUtils.isBlank( ai.getDescription() )
362                                     ? "No description in plugin's POM."
363                                     : StringUtils.abbreviate( ai.getDescription(), MAX_WIDTH ) );
364             System.out.println();
365         }
366 
367         System.out.println( "------" );
368         System.out.println( "Total record hits: " + response.getTotalHitsCount() );
369         System.out.println();
370     }
371 }