View Javadoc
1   package org.apache.maven.index;
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 javax.inject.Inject;
23  import javax.inject.Named;
24  import javax.inject.Singleton;
25  import java.io.File;
26  import java.io.IOException;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.concurrent.ConcurrentHashMap;
32  import org.apache.lucene.queryparser.classic.ParseException;
33  import org.apache.lucene.search.Query;
34  import org.apache.lucene.store.Directory;
35  import org.apache.lucene.store.FSDirectory;
36  import org.apache.maven.index.context.ContextMemberProvider;
37  import org.apache.maven.index.context.DefaultIndexingContext;
38  import org.apache.maven.index.context.ExistingLuceneIndexMismatchException;
39  import org.apache.maven.index.context.IndexCreator;
40  import org.apache.maven.index.context.IndexUtils;
41  import org.apache.maven.index.context.IndexingContext;
42  import org.apache.maven.index.context.MergedIndexingContext;
43  import org.apache.maven.index.context.StaticContextMemberProvider;
44  import org.apache.maven.index.context.UnsupportedExistingLuceneIndexException;
45  import org.apache.maven.index.expr.SearchExpression;
46  import org.apache.maven.index.util.IndexCreatorSorter;
47  import org.codehaus.plexus.util.FileUtils;
48  
49  /**
50   * A default {@link NexusIndexer} implementation.
51   *
52   * @author Tamas Cservenak
53   * @author Eugene Kuleshov
54   * @deprecated Use {@link Indexer} instead. Discouraged from further use, as it suffers from multiple synchronization
55   *             and other problems. As it tries to serve as "context registry" too, but it does not synchronize the
56   *             access to it, but also, introduces some extras (like "targeted" vs "non targeted" search), that makes
57   *             it's behavior less intuitive.
58   */
59  @Deprecated
60  @Singleton
61  @Named
62  public class DefaultNexusIndexer
63      implements NexusIndexer
64  {
65  
66      private final Indexer indexer;
67  
68      private final Scanner scanner;
69  
70      private final IndexerEngine indexerEngine;
71  
72      private final QueryCreator queryCreator;
73  
74      private final Map<String, IndexingContext> indexingContexts = new ConcurrentHashMap<String, IndexingContext>();
75  
76  
77      @Inject
78      public DefaultNexusIndexer( Indexer indexer,
79                                  Scanner scanner,
80                                  IndexerEngine indexerEngine,
81                                  QueryCreator queryCreator )
82      {
83          this.indexer = indexer;
84          this.scanner = scanner;
85          this.indexerEngine = indexerEngine;
86          this.queryCreator = queryCreator;
87      }
88  
89      // ----------------------------------------------------------------------------
90      // Contexts
91      // ----------------------------------------------------------------------------
92  
93      public void addIndexingContext( IndexingContext context )
94      {
95          indexingContexts.put( context.getId(), context );
96      }
97  
98      public IndexingContext addIndexingContext( String id, String repositoryId, File repository, File indexDirectory,
99          String repositoryUrl, String indexUpdateUrl,
100         List<? extends IndexCreator> indexers )
101         throws IOException, UnsupportedExistingLuceneIndexException
102     {
103         try
104         {
105             IndexingContext context =
106                 indexer.createIndexingContext( id, repositoryId, repository, indexDirectory, repositoryUrl,
107                                                indexUpdateUrl, true, false, indexers );
108             indexingContexts.put( context.getId(), context );
109             return context;
110         }
111         catch ( ExistingLuceneIndexMismatchException e )
112         {
113             throw new UnsupportedExistingLuceneIndexException( e.getMessage(), e );
114         }
115     }
116 
117     public IndexingContext addIndexingContextForced( String id, String repositoryId, File repository,
118         File indexDirectory, String repositoryUrl, String indexUpdateUrl,
119         List<? extends IndexCreator> indexers )
120         throws IOException
121     {
122         IndexingContext context =
123             indexer.createIndexingContext( id, repositoryId, repository, indexDirectory, repositoryUrl, indexUpdateUrl,
124                                            true, true, indexers );
125         indexingContexts.put( context.getId(), context );
126         return context;
127     }
128 
129     public IndexingContext addIndexingContext( String id, String repositoryId, File repository, Directory directory,
130         String repositoryUrl, String indexUpdateUrl,
131         List<? extends IndexCreator> indexers )
132         throws IOException, UnsupportedExistingLuceneIndexException
133     {
134         try
135         {
136             IndexingContext context =
137                 new DefaultIndexingContext( id, repositoryId, repository, directory, repositoryUrl, indexUpdateUrl,
138                                             IndexCreatorSorter.sort( indexers ), false );
139             indexingContexts.put( context.getId(), context );
140             return context;
141         }
142         catch ( ExistingLuceneIndexMismatchException e )
143         {
144             throw new UnsupportedExistingLuceneIndexException( e.getMessage(), e );
145         }
146     }
147 
148     public IndexingContext addIndexingContextForced( String id, String repositoryId, File repository,
149         Directory directory, String repositoryUrl, String indexUpdateUrl,
150         List<? extends IndexCreator> indexers )
151         throws IOException
152     {
153         IndexingContext context =
154             new DefaultIndexingContext( id, repositoryId, repository, directory, repositoryUrl, indexUpdateUrl,
155                                         IndexCreatorSorter.sort( indexers ), true );
156         indexingContexts.put( context.getId(), context );
157         return context;
158     }
159 
160     public IndexingContext addMergedIndexingContext( String id, String repositoryId, File repository,
161         File indexDirectory, boolean searchable,
162         Collection<IndexingContext> contexts )
163         throws IOException
164     {
165         return addMergedIndexingContext( id, repositoryId, repository, indexDirectory, searchable,
166                                          new StaticContextMemberProvider( contexts ) );
167     }
168 
169     public IndexingContext addMergedIndexingContext( String id, String repositoryId, File repository,
170         File indexDirectory, boolean searchable,
171         ContextMemberProvider membersProvider )
172         throws IOException
173     {
174         IndexingContext context =
175             indexer.createMergedIndexingContext( id, repositoryId, repository, indexDirectory, searchable,
176                                                  membersProvider );
177         indexingContexts.put( context.getId(), context );
178         return context;
179     }
180 
181     public IndexingContext addMergedIndexingContext( String id, String repositoryId, File repository,
182         Directory indexDirectory, boolean searchable,
183         Collection<IndexingContext> contexts )
184         throws IOException
185     {
186         IndexingContext context =
187             new MergedIndexingContext( id, repositoryId, repository, indexDirectory, searchable,
188                                        new StaticContextMemberProvider( contexts ) );
189         indexingContexts.put( context.getId(), context );
190         return context;
191     }
192 
193     public IndexingContext addMergedIndexingContext( String id, String repositoryId, File repository,
194         Directory indexDirectory, boolean searchable,
195         ContextMemberProvider membersProvider )
196         throws IOException
197     {
198         IndexingContext context =
199             new MergedIndexingContext( id, repositoryId, repository, indexDirectory, searchable, membersProvider );
200         indexingContexts.put( context.getId(), context );
201         return context;
202     }
203 
204     public void removeIndexingContext( IndexingContext context, boolean deleteFiles )
205         throws IOException
206     {
207         if ( indexingContexts.containsKey( context.getId() ) )
208         {
209             indexingContexts.remove( context.getId() );
210             indexer.closeIndexingContext( context, deleteFiles );
211         }
212     }
213 
214     public Map<String, IndexingContext> getIndexingContexts()
215     {
216         return Collections.unmodifiableMap( indexingContexts );
217     }
218 
219     // ----------------------------------------------------------------------------
220     // Scanning
221     // ----------------------------------------------------------------------------
222 
223     public void scan( final IndexingContext context )
224         throws IOException
225     {
226         scan( context, null );
227     }
228 
229     public void scan( final IndexingContext context, boolean update )
230         throws IOException
231     {
232         scan( context, null, update );
233     }
234 
235     public void scan( final IndexingContext context, final ArtifactScanningListener listener )
236         throws IOException
237     {
238         scan( context, listener, false );
239     }
240 
241     public void scan( final IndexingContext context, final ArtifactScanningListener listener, final boolean update )
242         throws IOException
243     {
244         scan( context, null, listener, update );
245     }
246 
247     /**
248      * Uses {@link Scanner} to scan repository content. A {@link ArtifactScanningListener} is used to process found
249      * artifacts and to add them to the index using
250      * {@link NexusIndexer#artifactDiscovered(ArtifactContext, IndexingContext)}.
251      *
252      * @see DefaultScannerListener
253      * @see #artifactDiscovered(ArtifactContext, IndexingContext)
254      */
255     public void scan( final IndexingContext context, final String fromPath, final ArtifactScanningListener listener,
256         final boolean update )
257         throws IOException
258     {
259         final File repositoryDirectory = context.getRepository();
260         if ( repositoryDirectory == null )
261         {
262             // nothing to scan
263             return;
264         }
265 
266         if ( !repositoryDirectory.exists() )
267         {
268             throw new IOException( "Repository directory " + repositoryDirectory + " does not exist" );
269         }
270 
271         // always use temporary context when reindexing
272         final File tmpFile = File.createTempFile( context.getId() + "-tmp", "" );
273         tmpFile.deleteOnExit();
274         final File tmpDir = new File( tmpFile.getParentFile(), tmpFile.getName() + ".dir" );
275         if ( !tmpDir.mkdirs() )
276         {
277             throw new IOException( "Cannot create temporary directory: " + tmpDir );
278         }
279 
280         IndexingContext tmpContext = null;
281         try
282         {
283             final FSDirectory directory = FSDirectory.open( tmpDir.toPath() );
284             if ( update )
285             {
286                 IndexUtils.copyDirectory( context.getIndexDirectory(), directory );
287             }
288             tmpContext = new DefaultIndexingContext( context.getId() + "-tmp", //
289                                                      context.getRepositoryId(), //
290                                                      context.getRepository(), //
291                                                      directory, //
292                                                      context.getRepositoryUrl(), //
293                                                      context.getIndexUpdateUrl(), //
294                                                      context.getIndexCreators(), //
295                                                      true );
296 
297             scanner.scan( new ScanningRequest( tmpContext, //
298                                                new DefaultScannerListener( tmpContext, indexerEngine,
299                                                                            update, listener ), fromPath ) );
300 
301             tmpContext.updateTimestamp( true );
302             context.replace( tmpContext.getIndexDirectory() );
303         }
304         catch ( Exception ex )
305         {
306             throw (IOException) new IOException( "Error scanning context " + context.getId() + ": " + ex ).initCause(
307                 ex );
308         }
309         finally
310         {
311             if ( tmpContext != null )
312             {
313                 tmpContext.close( true );
314             }
315 
316             if ( tmpFile.exists() )
317             {
318                 tmpFile.delete();
319             }
320 
321             FileUtils.deleteDirectory( tmpDir );
322         }
323     }
324 
325     /**
326      * Delegates to the {@link IndexerEngine} to add a new artifact to the index
327      */
328     public void artifactDiscovered( ArtifactContext ac, IndexingContext context )
329         throws IOException
330     {
331         if ( ac != null )
332         {
333             indexerEngine.index( context, ac );
334         }
335     }
336 
337     // ----------------------------------------------------------------------------
338     // Modifying
339     // ----------------------------------------------------------------------------
340 
341     /**
342      * Delegates to the {@link IndexerEngine} to update artifact to the index
343      */
344     public void addArtifactToIndex( ArtifactContext ac, IndexingContext context )
345         throws IOException
346     {
347         indexer.addArtifactsToIndex( Collections.singleton( ac ), context );
348     }
349 
350     public void addArtifactsToIndex( Collection<ArtifactContext> acs, IndexingContext context )
351         throws IOException
352     {
353         indexer.addArtifactsToIndex( acs, context );
354     }
355 
356     /**
357      * Delegates to the {@link IndexerEngine} to remove artifact from the index
358      */
359     public void deleteArtifactFromIndex( ArtifactContext ac, IndexingContext context )
360         throws IOException
361     {
362         indexer.deleteArtifactsFromIndex( Collections.singleton( ac ), context );
363     }
364 
365     public void deleteArtifactsFromIndex( Collection<ArtifactContext> acs, IndexingContext context )
366         throws IOException
367     {
368         indexer.deleteArtifactsFromIndex( acs, context );
369     }
370 
371     // ----------------------------------------------------------------------------
372     // Searching
373     // ----------------------------------------------------------------------------
374 
375     public FlatSearchResponse searchFlat( FlatSearchRequest request )
376         throws IOException
377     {
378         if ( request.getContexts().isEmpty() )
379         {
380             request.getContexts().addAll( getIndexingContexts().values() );
381         }
382         return indexer.searchFlat( request );
383     }
384 
385     public IteratorSearchResponse searchIterator( IteratorSearchRequest request )
386         throws IOException
387     {
388         if ( request.getContexts().isEmpty() )
389         {
390             request.getContexts().addAll( getIndexingContexts().values() );
391         }
392         return indexer.searchIterator( request );
393     }
394 
395     public GroupedSearchResponse searchGrouped( GroupedSearchRequest request )
396         throws IOException
397     {
398         if ( request.getContexts().isEmpty() )
399         {
400             request.getContexts().addAll( getIndexingContexts().values() );
401         }
402         return indexer.searchGrouped( request );
403     }
404 
405     // ----------------------------------------------------------------------------
406     // Query construction
407     // ----------------------------------------------------------------------------
408 
409     @Deprecated
410     public Query constructQuery( Field field, String query, SearchType type )
411         throws IllegalArgumentException
412     {
413         try
414         {
415             return queryCreator.constructQuery( field, query, type );
416         }
417         catch ( ParseException e )
418         {
419             throw new IllegalArgumentException( e );
420         }
421     }
422 
423     public Query constructQuery( Field field, SearchExpression expression )
424         throws IllegalArgumentException
425     {
426         return indexer.constructQuery( field, expression );
427     }
428 
429     // ----------------------------------------------------------------------------
430     // Identification
431     // ----------------------------------------------------------------------------
432 
433     public Collection<ArtifactInfo> identify( Field field, String query )
434         throws IllegalArgumentException, IOException
435     {
436         return identify( constructQuery( field, query, SearchType.EXACT ) );
437     }
438 
439     public Collection<ArtifactInfo> identify( File artifact )
440         throws IOException
441     {
442         return identify( artifact, indexingContexts.values() );
443     }
444 
445     public Collection<ArtifactInfo> identify( File artifact, Collection<IndexingContext> contexts )
446         throws IOException
447     {
448         return indexer.identify( artifact, contexts );
449     }
450 
451     public Collection<ArtifactInfo> identify( Query query )
452         throws IOException
453     {
454         return identify( query, indexingContexts.values() );
455     }
456 
457     public Collection<ArtifactInfo> identify( Query query, Collection<IndexingContext> contexts )
458         throws IOException
459     {
460         return indexer.identify( query, contexts );
461     }
462 }