package org.apache.maven.indexer.examples; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.MultiFields; import org.apache.lucene.search.BooleanClause.Occur; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.util.Bits; import org.apache.maven.index.ArtifactInfo; import org.apache.maven.index.ArtifactInfoFilter; import org.apache.maven.index.ArtifactInfoGroup; import org.apache.maven.index.Field; import org.apache.maven.index.FlatSearchRequest; import org.apache.maven.index.FlatSearchResponse; import org.apache.maven.index.GroupedSearchRequest; import org.apache.maven.index.GroupedSearchResponse; import org.apache.maven.index.Grouping; import org.apache.maven.index.Indexer; import org.apache.maven.index.IteratorSearchRequest; import org.apache.maven.index.IteratorSearchResponse; import org.apache.maven.index.MAVEN; import org.apache.maven.index.context.IndexCreator; import org.apache.maven.index.context.IndexUtils; import org.apache.maven.index.context.IndexingContext; import org.apache.maven.index.expr.SourcedSearchExpression; import org.apache.maven.index.expr.UserInputSearchExpression; import org.apache.maven.index.search.grouping.GAGrouping; import org.apache.maven.index.updater.IndexUpdateRequest; import org.apache.maven.index.updater.IndexUpdateResult; import org.apache.maven.index.updater.IndexUpdater; import org.apache.maven.index.updater.ResourceFetcher; import org.apache.maven.index.updater.WagonHelper; import org.apache.maven.wagon.Wagon; import org.apache.maven.wagon.events.TransferEvent; import org.apache.maven.wagon.events.TransferListener; import org.apache.maven.wagon.observers.AbstractTransferListener; import org.codehaus.plexus.DefaultContainerConfiguration; import org.codehaus.plexus.DefaultPlexusContainer; import org.codehaus.plexus.PlexusConstants; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.PlexusContainerException; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.codehaus.plexus.util.StringUtils; import org.eclipse.aether.util.version.GenericVersionScheme; import org.eclipse.aether.version.InvalidVersionSpecificationException; import org.eclipse.aether.version.Version; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; public class BasicUsageExample { public static void main( String[] args ) throws Exception { final BasicUsageExample basicUsageExample = new BasicUsageExample(); basicUsageExample.perform(); } // == private final PlexusContainer plexusContainer; private final Indexer indexer; private final IndexUpdater indexUpdater; private final Wagon httpWagon; private IndexingContext centralContext; public BasicUsageExample() throws PlexusContainerException, ComponentLookupException { // here we create Plexus container, the Maven default IoC container // Plexus falls outside of MI scope, just accept the fact that // MI is a Plexus component ;) // If needed more info, ask on Maven Users list or Plexus Users list // google is your friend! final DefaultContainerConfiguration config = new DefaultContainerConfiguration(); config.setClassPathScanning( PlexusConstants.SCANNING_INDEX ); this.plexusContainer = new DefaultPlexusContainer( config ); // lookup the indexer components from plexus this.indexer = plexusContainer.lookup( Indexer.class ); this.indexUpdater = plexusContainer.lookup( IndexUpdater.class ); // lookup wagon used to remotely fetch index this.httpWagon = plexusContainer.lookup( Wagon.class, "http" ); } public void perform() throws IOException, ComponentLookupException, InvalidVersionSpecificationException { // Files where local cache is (if any) and Lucene Index should be located File centralLocalCache = new File( "target/central-cache" ); File centralIndexDir = new File( "target/central-index" ); // Creators we want to use (search for fields it defines) List<IndexCreator> indexers = new ArrayList<IndexCreator>(); indexers.add( plexusContainer.lookup( IndexCreator.class, "min" ) ); indexers.add( plexusContainer.lookup( IndexCreator.class, "jarContent" ) ); indexers.add( plexusContainer.lookup( IndexCreator.class, "maven-plugin" ) ); // Create context for central repository index centralContext = indexer.createIndexingContext( "central-context", "central", centralLocalCache, centralIndexDir, "http://repo1.maven.org/maven2", null, true, true, indexers ); // Update the index (incremental update will happen if this is not 1st run and files are not deleted) // This whole block below should not be executed on every app start, but rather controlled by some configuration // since this block will always emit at least one HTTP GET. Central indexes are updated once a week, but // other index sources might have different index publishing frequency. // Preferred frequency is once a week. if ( true ) { System.out.println( "Updating Index..." ); System.out.println( "This might take a while on first run, so please be patient!" ); // Create ResourceFetcher implementation to be used with IndexUpdateRequest // Here, we use Wagon based one as shorthand, but all we need is a ResourceFetcher implementation TransferListener listener = new AbstractTransferListener() { public void transferStarted( TransferEvent transferEvent ) { System.out.print( " Downloading " + transferEvent.getResource().getName() ); } public void transferProgress( TransferEvent transferEvent, byte[] buffer, int length ) { } public void transferCompleted( TransferEvent transferEvent ) { System.out.println( " - Done" ); } }; ResourceFetcher resourceFetcher = new WagonHelper.WagonFetcher( httpWagon, listener, null, null ); Date centralContextCurrentTimestamp = centralContext.getTimestamp(); IndexUpdateRequest updateRequest = new IndexUpdateRequest( centralContext, resourceFetcher ); IndexUpdateResult updateResult = indexUpdater.fetchAndUpdateIndex( updateRequest ); if ( updateResult.isFullUpdate() ) { System.out.println( "Full update happened!" ); } else if ( updateResult.getTimestamp().equals( centralContextCurrentTimestamp ) ) { System.out.println( "No update needed, index is up to date!" ); } else { System.out.println( "Incremental update happened, change covered " + centralContextCurrentTimestamp + " - " + updateResult.getTimestamp() + " period." ); } System.out.println(); } System.out.println(); System.out.println( "Using index" ); System.out.println( "===========" ); System.out.println(); // ==== // Case: // dump all the GAVs // NOTE: will not actually execute do this below, is too long to do (Central is HUGE), but is here as code // example if ( false ) { final IndexSearcher searcher = centralContext.acquireIndexSearcher(); try { final IndexReader ir = searcher.getIndexReader(); Bits liveDocs = MultiFields.getLiveDocs( ir ); for ( int i = 0; i < ir.maxDoc(); i++ ) { if ( liveDocs == null || liveDocs.get( i ) ) { final Document doc = ir.document( i ); final ArtifactInfo ai = IndexUtils.constructArtifactInfo( doc, centralContext ); System.out.println( ai.getGroupId() + ":" + ai.getArtifactId() + ":" + ai.getVersion() + ":" + ai.getClassifier() + " (sha1=" + ai.getSha1() + ")" ); } } } finally { centralContext.releaseIndexSearcher( searcher ); } } // ==== // Case: // Search for all GAVs with known G and A and having version greater than V final GenericVersionScheme versionScheme = new GenericVersionScheme(); final String versionString = "1.5.0"; final Version version = versionScheme.parseVersion( versionString ); // construct the query for known GA final Query groupIdQ = indexer.constructQuery( MAVEN.GROUP_ID, new SourcedSearchExpression( "org.sonatype.nexus" ) ); final Query artifactIdQ = indexer.constructQuery( MAVEN.ARTIFACT_ID, new SourcedSearchExpression( "nexus-api" ) ); final BooleanQuery query = new BooleanQuery(); query.add( groupIdQ, Occur.MUST ); query.add( artifactIdQ, Occur.MUST ); // we want "jar" artifacts only query.add( indexer.constructQuery( MAVEN.PACKAGING, new SourcedSearchExpression( "jar" ) ), Occur.MUST ); // we want main artifacts only (no classifier) // Note: this below is unfinished API, needs fixing query.add( indexer.constructQuery( MAVEN.CLASSIFIER, new SourcedSearchExpression( Field.NOT_PRESENT ) ), Occur.MUST_NOT ); // construct the filter to express "V greater than" final ArtifactInfoFilter versionFilter = new ArtifactInfoFilter() { public boolean accepts( final IndexingContext ctx, final ArtifactInfo ai ) { try { final Version aiV = versionScheme.parseVersion( ai.getVersion() ); // Use ">=" if you are INCLUSIVE return aiV.compareTo( version ) > 0; } catch ( InvalidVersionSpecificationException e ) { // do something here? be safe and include? return true; } } }; System.out.println( "Searching for all GAVs with G=org.sonatype.nexus and nexus-api and having V greater than 1.5.0" ); final IteratorSearchRequest request = new IteratorSearchRequest( query, Collections.singletonList( centralContext ), versionFilter ); final IteratorSearchResponse response = indexer.searchIterator( request ); for ( ArtifactInfo ai : response ) { System.out.println( ai.toString() ); } // Case: // Use index // Searching for some artifact Query gidQ = indexer.constructQuery( MAVEN.GROUP_ID, new SourcedSearchExpression( "org.apache.maven.indexer" ) ); Query aidQ = indexer.constructQuery( MAVEN.ARTIFACT_ID, new SourcedSearchExpression( "indexer-artifact" ) ); BooleanQuery bq = new BooleanQuery(); bq.add( gidQ, Occur.MUST ); bq.add( aidQ, Occur.MUST ); searchAndDump( indexer, "all artifacts under GA org.apache.maven.indexer:indexer-artifact", bq ); // Searching for some main artifact bq = new BooleanQuery(); bq.add( gidQ, Occur.MUST ); bq.add( aidQ, Occur.MUST ); // bq.add( nexusIndexer.constructQuery( MAVEN.CLASSIFIER, new SourcedSearchExpression( "*" ) ), Occur.MUST_NOT // ); searchAndDump( indexer, "main artifacts under GA org.apache.maven.indexer:indexer-artifact", bq ); // doing sha1 search searchAndDump( indexer, "SHA1 7ab67e6b20e5332a7fb4fdf2f019aec4275846c2", indexer.constructQuery( MAVEN.SHA1, new SourcedSearchExpression( "7ab67e6b20e5332a7fb4fdf2f019aec4275846c2" ) ) ); searchAndDump( indexer, "SHA1 7ab67e6b20 (partial hash)", indexer.constructQuery( MAVEN.SHA1, new UserInputSearchExpression( "7ab67e6b20" ) ) ); // doing classname search (incomplete classname) searchAndDump( indexer, "classname DefaultNexusIndexer (note: Central does not publish classes in the index)", indexer.constructQuery( MAVEN.CLASSNAMES, new UserInputSearchExpression( "DefaultNexusIndexer" ) ) ); // doing search for all "canonical" maven plugins latest versions bq = new BooleanQuery(); bq.add( indexer.constructQuery( MAVEN.PACKAGING, new SourcedSearchExpression( "maven-plugin" ) ), Occur.MUST ); bq.add( indexer.constructQuery( MAVEN.GROUP_ID, new SourcedSearchExpression( "org.apache.maven.plugins" ) ), Occur.MUST ); searchGroupedAndDump( indexer, "all \"canonical\" maven plugins", bq, new GAGrouping() ); // doing search for all archetypes latest versions searchGroupedAndDump( indexer, "all maven archetypes (latest versions)", indexer.constructQuery( MAVEN.PACKAGING, new SourcedSearchExpression( "maven-archetype" ) ), new GAGrouping() ); // close cleanly indexer.closeIndexingContext( centralContext, false ); } public void searchAndDump( Indexer nexusIndexer, String descr, Query q ) throws IOException { System.out.println( "Searching for " + descr ); FlatSearchResponse response = nexusIndexer.searchFlat( new FlatSearchRequest( q, centralContext ) ); for ( ArtifactInfo ai : response.getResults() ) { System.out.println( ai.toString() ); } System.out.println( "------" ); System.out.println( "Total: " + response.getTotalHitsCount() ); System.out.println(); } public void searchGroupedAndDump( Indexer nexusIndexer, String descr, Query q, Grouping g ) throws IOException { System.out.println( "Searching for " + descr ); GroupedSearchResponse response = nexusIndexer.searchGrouped( new GroupedSearchRequest( q, g, centralContext ) ); for ( Map.Entry<String, ArtifactInfoGroup> entry : response.getResults().entrySet() ) { ArtifactInfo ai = entry.getValue().getArtifactInfos().iterator().next(); System.out.println( "* Entry " + ai ); System.out.println( " Latest version: " + ai.getVersion() ); System.out.println( StringUtils.isBlank( ai.getDescription() ) ? "No description in plugin's POM." : StringUtils.abbreviate( ai.getDescription(), 60 ) ); System.out.println(); } System.out.println( "------" ); System.out.println( "Total record hits: " + response.getTotalHitsCount() ); System.out.println(); } }