View Javadoc
1   package org.apache.maven.index.examples.indexing;
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.analysis.core.WhitespaceAnalyzer;
23  import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
24  import org.apache.lucene.queryparser.classic.ParseException;
25  import org.apache.lucene.search.BooleanQuery;
26  import org.apache.lucene.search.Query;
27  import org.apache.maven.index.ArtifactContext;
28  import org.apache.maven.index.ArtifactInfo;
29  import org.apache.maven.index.ArtifactScanningListener;
30  import org.apache.maven.index.FlatSearchRequest;
31  import org.apache.maven.index.FlatSearchResponse;
32  import org.apache.maven.index.Indexer;
33  import org.apache.maven.index.MAVEN;
34  import org.apache.maven.index.Scanner;
35  import org.apache.maven.index.ScanningRequest;
36  import org.apache.maven.index.ScanningResult;
37  import org.apache.maven.index.context.IndexCreator;
38  import org.apache.maven.index.context.IndexingContext;
39  import org.apache.maven.index.expr.SourcedSearchExpression;
40  import org.slf4j.Logger;
41  import org.slf4j.LoggerFactory;
42  
43  import java.io.File;
44  import java.io.IOException;
45  import java.util.ArrayList;
46  import java.util.Collection;
47  import java.util.List;
48  import java.util.Set;
49  
50  import static java.util.Arrays.asList;
51  import static org.apache.lucene.search.BooleanClause.Occur.MUST;
52  
53  /**
54   * This class provides means to index and search for artifacts in a repository on the file system.
55   *
56   * @author mtodorov
57   */
58  public class RepositoryIndexer
59  {
60  
61      private static final Logger LOGGER = LoggerFactory.getLogger( RepositoryIndexer.class );
62  
63      private static final String[] LUCENE_FIELDS = new String[]{"g", "a", "v", "p", "c" };
64  
65      private static final WhitespaceAnalyzer LUCENE_ANALYZER = new WhitespaceAnalyzer( );
66  
67      private Indexer indexer;
68  
69      private Scanner scanner;
70  
71      private List<IndexCreator> indexers;
72  
73      private IndexingContext indexingContext;
74  
75      private String repositoryId;
76  
77      private File repositoryBasedir;
78  
79      private File indexDir;
80  
81  
82      public RepositoryIndexer()
83      {
84          // no op
85      }
86  
87      public void close()
88          throws IOException
89      {
90          indexer.closeIndexingContext( indexingContext, false );
91      }
92  
93      public void close( boolean deleteFiles )
94          throws IOException
95      {
96          indexingContext.close( deleteFiles );
97      }
98  
99      public void delete( final Collection<ArtifactInfo> artifacts )
100         throws IOException
101     {
102         final List<ArtifactContext> delete = new ArrayList<>();
103         for ( final ArtifactInfo artifact : artifacts )
104         {
105             LOGGER.debug( "Deleting artifact: {}; ctx id: {}; idx dir: {}",
106                           artifact, indexingContext.getId(), indexingContext.getIndexDirectory() );
107 
108             delete.add( new ArtifactContext( null, null, null, artifact, null ) );
109         }
110 
111         getIndexer().deleteArtifactsFromIndex( delete, indexingContext );
112     }
113 
114     public Set<ArtifactInfo> search( final String groupId, final String artifactId, final String version,
115                                      final String packaging, final String classifier )
116         throws IOException
117     {
118         final BooleanQuery.Builder queryBuilder = new BooleanQuery.Builder();
119 
120         if ( groupId != null )
121         {
122             queryBuilder.add( getIndexer().constructQuery( MAVEN.GROUP_ID,
123                     new SourcedSearchExpression( groupId ) ), MUST );
124         }
125 
126         if ( artifactId != null )
127         {
128             queryBuilder.add( getIndexer().constructQuery( MAVEN.ARTIFACT_ID,
129                     new SourcedSearchExpression( artifactId ) ), MUST );
130         }
131 
132         if ( version != null )
133         {
134             queryBuilder.add( getIndexer().constructQuery( MAVEN.VERSION,
135                     new SourcedSearchExpression( version ) ), MUST );
136         }
137 
138         if ( packaging != null )
139         {
140             queryBuilder.add( getIndexer().constructQuery( MAVEN.PACKAGING,
141                     new SourcedSearchExpression( packaging ) ), MUST );
142         }
143         else
144         {
145             // Fallback to jar
146             queryBuilder.add( getIndexer().constructQuery( MAVEN.PACKAGING,
147                     new SourcedSearchExpression( "jar" ) ), MUST );
148         }
149 
150         if ( classifier != null )
151         {
152             queryBuilder.add( getIndexer().constructQuery( MAVEN.CLASSIFIER,
153                     new SourcedSearchExpression( classifier ) ),
154                        MUST );
155         }
156 
157         Query query = queryBuilder.build();
158 
159         LOGGER.debug( "Executing search query: {}; ctx id: {}; idx dir: {}",
160                       query, indexingContext.getId(), indexingContext.getIndexDirectory() );
161 
162         final FlatSearchResponse response = getIndexer().searchFlat( new FlatSearchRequest( query, indexingContext ) );
163 
164         LOGGER.info( "Hit count: {}", response.getReturnedHitsCount() );
165 
166         final Set<ArtifactInfo> results = response.getResults();
167         if ( LOGGER.isDebugEnabled() )
168         {
169             for ( final ArtifactInfo result : results )
170             {
171                 LOGGER.debug( "Found artifact: {}", result.toString() );
172             }
173         }
174 
175         return results;
176     }
177 
178     public Set<ArtifactInfo> search( final String queryText )
179         throws ParseException, IOException
180     {
181         final Query query = new MultiFieldQueryParser( LUCENE_FIELDS, LUCENE_ANALYZER ).parse( queryText );
182 
183         LOGGER.debug( "Executing search query: {}; ctx id: {}; idx dir: {}",
184                       query, indexingContext.getId(), indexingContext.getIndexDirectory() );
185 
186         final FlatSearchResponse response = getIndexer().searchFlat( new FlatSearchRequest( query, indexingContext ) );
187 
188         final Set<ArtifactInfo> results = response.getResults();
189         if ( LOGGER.isDebugEnabled() )
190         {
191             LOGGER.debug( "Hit count: {}", response.getReturnedHitsCount() );
192 
193             for ( final ArtifactInfo result : results )
194             {
195                 LOGGER.debug( "Found artifact: {}; uinfo: {}", result.toString(), result.getUinfo() );
196             }
197         }
198 
199         return results;
200     }
201 
202     public Set<ArtifactInfo> searchBySHA1( final String checksum )
203         throws IOException
204     {
205         final BooleanQuery query = new BooleanQuery.Builder()
206                 .add( getIndexer().constructQuery( MAVEN.SHA1, new SourcedSearchExpression( checksum ) ), MUST )
207                 .build();
208 
209         LOGGER.debug( "Executing search query: {}; ctx id: {}; idx dir: {}",
210                       query, indexingContext.getId(), indexingContext.getIndexDirectory() );
211 
212         final FlatSearchResponse response = getIndexer().searchFlat( new FlatSearchRequest( query, indexingContext ) );
213 
214         LOGGER.info( "Hit count: {}", response.getReturnedHitsCount() );
215 
216         final Set<ArtifactInfo> results = response.getResults();
217         if ( LOGGER.isDebugEnabled() )
218         {
219             for ( final ArtifactInfo result : results )
220             {
221                 LOGGER.debug( "Found artifact: {}", result.toString() );
222             }
223         }
224 
225         return results;
226     }
227 
228     public int index( final File startingPath )
229     {
230         final ScanningResult scan = getScanner().scan(
231             new ScanningRequest( indexingContext, new ReindexArtifactScanningListener(),
232                                  startingPath == null ? "." : startingPath.getPath() ) );
233         return scan.getTotalFiles();
234     }
235 
236     public void addArtifactToIndex( final File artifactFile, final ArtifactInfo artifactInfo )
237         throws IOException
238     {
239         getIndexer().addArtifactsToIndex(
240                 asList( new ArtifactContext( null, artifactFile, null, artifactInfo, null ) ),
241                 indexingContext );
242     }
243 
244     public void addArtifactToIndex( String repository, File artifactFile, String groupId, String artifactId,
245                                     String version, String extension, String classifier )
246         throws IOException
247     {
248         ArtifactInfo artifactInfo = new ArtifactInfo( repository, groupId, artifactId, version, classifier, extension );
249         if ( extension != null )
250         {
251             artifactInfo.setFieldValue( MAVEN.EXTENSION, extension );
252         }
253 
254         LOGGER.debug( "Adding artifact: {}; repo: {}; type: {}", artifactInfo.getUinfo(), repository, extension );
255 
256         getIndexer().addArtifactsToIndex(
257             asList( new ArtifactContext( null, artifactFile, null, artifactInfo, artifactInfo.calculateGav() ) ),
258             indexingContext );
259     }
260 
261     private class ReindexArtifactScanningListener
262         implements ArtifactScanningListener
263     {
264 
265         int totalFiles = 0;
266 
267         private IndexingContext context;
268 
269         @Override
270         public void scanningStarted( final IndexingContext context )
271         {
272             this.context = context;
273         }
274 
275         @Override
276         public void scanningFinished( final IndexingContext context, final ScanningResult result )
277         {
278             result.setTotalFiles( totalFiles );
279             LOGGER.debug( "Scanning finished; total files: {}; has exception: {}", result.getTotalFiles(),
280                           result.hasExceptions() );
281         }
282 
283         @Override
284         public void artifactError( final ArtifactContext ac, final Exception ex )
285         {
286             LOGGER.error( "Artifact error!", ex );
287         }
288 
289         @Override
290         public void artifactDiscovered( final ArtifactContext ac )
291         {
292             try
293             {
294                 LOGGER.debug( "Adding artifact gav: {}; ctx id: {}; idx dir: {}",
295                         ac.getGav(), context.getId(), context.getIndexDirectory() );
296 
297                 getIndexer().addArtifactsToIndex( asList( ac ), context );
298                 totalFiles++;
299             }
300             catch ( IOException ex )
301             {
302                 LOGGER.error( "Artifact index error", ex );
303             }
304         }
305     }
306 
307     public Indexer getIndexer()
308     {
309         return indexer;
310     }
311 
312     public void setIndexer( Indexer indexer )
313     {
314         this.indexer = indexer;
315     }
316 
317     public Scanner getScanner()
318     {
319         return scanner;
320     }
321 
322     public void setScanner( Scanner scanner )
323     {
324         this.scanner = scanner;
325     }
326 
327     public List<IndexCreator> getIndexers()
328     {
329         return indexers;
330     }
331 
332     public void setIndexers( List<IndexCreator> indexers )
333     {
334         this.indexers = indexers;
335     }
336 
337     public IndexingContext getIndexingContext()
338     {
339         return indexingContext;
340     }
341 
342     public void setIndexingContext( IndexingContext indexingContext )
343     {
344         this.indexingContext = indexingContext;
345     }
346 
347     public String getRepositoryId()
348     {
349         return repositoryId;
350     }
351 
352     public void setRepositoryId( String repositoryId )
353     {
354         this.repositoryId = repositoryId;
355     }
356 
357     public File getRepositoryBasedir()
358     {
359         return repositoryBasedir;
360     }
361 
362     public void setRepositoryBasedir( File repositoryBasedir )
363     {
364         this.repositoryBasedir = repositoryBasedir;
365     }
366 
367     public File getIndexDir()
368     {
369         return indexDir;
370     }
371 
372     public void setIndexDir( File indexDir )
373     {
374         this.indexDir = indexDir;
375     }
376 
377 }