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