package org.apache.maven.index; /* * 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 javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.search.Query; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.maven.index.context.ContextMemberProvider; import org.apache.maven.index.context.DefaultIndexingContext; import org.apache.maven.index.context.ExistingLuceneIndexMismatchException; 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.context.MergedIndexingContext; import org.apache.maven.index.context.StaticContextMemberProvider; import org.apache.maven.index.context.UnsupportedExistingLuceneIndexException; import org.apache.maven.index.expr.SearchExpression; import org.apache.maven.index.util.IndexCreatorSorter; import org.codehaus.plexus.util.FileUtils; /** * A default {@link NexusIndexer} implementation. * * @author Tamas Cservenak * @author Eugene Kuleshov * @deprecated Use {@link Indexer} instead. Discouraged from further use, as it suffers from multiple synchronization * and other problems. As it tries to serve as "context registry" too, but it does not synchronize the * access to it, but also, introduces some extras (like "targeted" vs "non targeted" search), that makes * it's behavior less intuitive. */ @Deprecated @Singleton @Named public class DefaultNexusIndexer implements NexusIndexer { private final Indexer indexer; private final Scanner scanner; private final IndexerEngine indexerEngine; private final QueryCreator queryCreator; private final Map<String, IndexingContext> indexingContexts = new ConcurrentHashMap<String, IndexingContext>(); @Inject public DefaultNexusIndexer( Indexer indexer, Scanner scanner, IndexerEngine indexerEngine, QueryCreator queryCreator ) { this.indexer = indexer; this.scanner = scanner; this.indexerEngine = indexerEngine; this.queryCreator = queryCreator; } // ---------------------------------------------------------------------------- // Contexts // ---------------------------------------------------------------------------- public void addIndexingContext( IndexingContext context ) { indexingContexts.put( context.getId(), context ); } public IndexingContext addIndexingContext( String id, String repositoryId, File repository, File indexDirectory, String repositoryUrl, String indexUpdateUrl, List<? extends IndexCreator> indexers ) throws IOException, UnsupportedExistingLuceneIndexException { try { IndexingContext context = indexer.createIndexingContext( id, repositoryId, repository, indexDirectory, repositoryUrl, indexUpdateUrl, true, false, indexers ); indexingContexts.put( context.getId(), context ); return context; } catch ( ExistingLuceneIndexMismatchException e ) { throw new UnsupportedExistingLuceneIndexException( e.getMessage(), e ); } } public IndexingContext addIndexingContextForced( String id, String repositoryId, File repository, File indexDirectory, String repositoryUrl, String indexUpdateUrl, List<? extends IndexCreator> indexers ) throws IOException { IndexingContext context = indexer.createIndexingContext( id, repositoryId, repository, indexDirectory, repositoryUrl, indexUpdateUrl, true, true, indexers ); indexingContexts.put( context.getId(), context ); return context; } public IndexingContext addIndexingContext( String id, String repositoryId, File repository, Directory directory, String repositoryUrl, String indexUpdateUrl, List<? extends IndexCreator> indexers ) throws IOException, UnsupportedExistingLuceneIndexException { try { IndexingContext context = new DefaultIndexingContext( id, repositoryId, repository, directory, repositoryUrl, indexUpdateUrl, IndexCreatorSorter.sort( indexers ), false ); indexingContexts.put( context.getId(), context ); return context; } catch ( ExistingLuceneIndexMismatchException e ) { throw new UnsupportedExistingLuceneIndexException( e.getMessage(), e ); } } public IndexingContext addIndexingContextForced( String id, String repositoryId, File repository, Directory directory, String repositoryUrl, String indexUpdateUrl, List<? extends IndexCreator> indexers ) throws IOException { IndexingContext context = new DefaultIndexingContext( id, repositoryId, repository, directory, repositoryUrl, indexUpdateUrl, IndexCreatorSorter.sort( indexers ), true ); indexingContexts.put( context.getId(), context ); return context; } public IndexingContext addMergedIndexingContext( String id, String repositoryId, File repository, File indexDirectory, boolean searchable, Collection<IndexingContext> contexts ) throws IOException { return addMergedIndexingContext( id, repositoryId, repository, indexDirectory, searchable, new StaticContextMemberProvider( contexts ) ); } public IndexingContext addMergedIndexingContext( String id, String repositoryId, File repository, File indexDirectory, boolean searchable, ContextMemberProvider membersProvider ) throws IOException { IndexingContext context = indexer.createMergedIndexingContext( id, repositoryId, repository, indexDirectory, searchable, membersProvider ); indexingContexts.put( context.getId(), context ); return context; } public IndexingContext addMergedIndexingContext( String id, String repositoryId, File repository, Directory indexDirectory, boolean searchable, Collection<IndexingContext> contexts ) throws IOException { IndexingContext context = new MergedIndexingContext( id, repositoryId, repository, indexDirectory, searchable, new StaticContextMemberProvider( contexts ) ); indexingContexts.put( context.getId(), context ); return context; } public IndexingContext addMergedIndexingContext( String id, String repositoryId, File repository, Directory indexDirectory, boolean searchable, ContextMemberProvider membersProvider ) throws IOException { IndexingContext context = new MergedIndexingContext( id, repositoryId, repository, indexDirectory, searchable, membersProvider ); indexingContexts.put( context.getId(), context ); return context; } public void removeIndexingContext( IndexingContext context, boolean deleteFiles ) throws IOException { if ( indexingContexts.containsKey( context.getId() ) ) { indexingContexts.remove( context.getId() ); indexer.closeIndexingContext( context, deleteFiles ); } } public Map<String, IndexingContext> getIndexingContexts() { return Collections.unmodifiableMap( indexingContexts ); } // ---------------------------------------------------------------------------- // Scanning // ---------------------------------------------------------------------------- public void scan( final IndexingContext context ) throws IOException { scan( context, null ); } public void scan( final IndexingContext context, boolean update ) throws IOException { scan( context, null, update ); } public void scan( final IndexingContext context, final ArtifactScanningListener listener ) throws IOException { scan( context, listener, false ); } public void scan( final IndexingContext context, final ArtifactScanningListener listener, final boolean update ) throws IOException { scan( context, null, listener, update ); } /** * Uses {@link Scanner} to scan repository content. A {@link ArtifactScanningListener} is used to process found * artifacts and to add them to the index using * {@link NexusIndexer#artifactDiscovered(ArtifactContext, IndexingContext)}. * * @see DefaultScannerListener * @see #artifactDiscovered(ArtifactContext, IndexingContext) */ public void scan( final IndexingContext context, final String fromPath, final ArtifactScanningListener listener, final boolean update ) throws IOException { final File repositoryDirectory = context.getRepository(); if ( repositoryDirectory == null ) { // nothing to scan return; } if ( !repositoryDirectory.exists() ) { throw new IOException( "Repository directory " + repositoryDirectory + " does not exist" ); } // always use temporary context when reindexing final File tmpFile = File.createTempFile( context.getId() + "-tmp", "" ); final File tmpDir = new File( tmpFile.getParentFile(), tmpFile.getName() + ".dir" ); if ( !tmpDir.mkdirs() ) { throw new IOException( "Cannot create temporary directory: " + tmpDir ); } IndexingContext tmpContext = null; try { final FSDirectory directory = FSDirectory.open( tmpDir.toPath() ); if ( update ) { IndexUtils.copyDirectory( context.getIndexDirectory(), directory ); } tmpContext = new DefaultIndexingContext( context.getId() + "-tmp", // context.getRepositoryId(), // context.getRepository(), // directory, // context.getRepositoryUrl(), // context.getIndexUpdateUrl(), // context.getIndexCreators(), // true ); scanner.scan( new ScanningRequest( tmpContext, // new DefaultScannerListener( tmpContext, indexerEngine, update, listener ), fromPath ) ); tmpContext.updateTimestamp( true ); context.replace( tmpContext.getIndexDirectory() ); } catch ( Exception ex ) { throw (IOException) new IOException( "Error scanning context " + context.getId() + ": " + ex ).initCause( ex ); } finally { if ( tmpContext != null ) { tmpContext.close( true ); } if ( tmpFile.exists() ) { tmpFile.delete(); } FileUtils.deleteDirectory( tmpDir ); } } /** * Delegates to the {@link IndexerEngine} to add a new artifact to the index */ public void artifactDiscovered( ArtifactContext ac, IndexingContext context ) throws IOException { if ( ac != null ) { indexerEngine.index( context, ac ); } } // ---------------------------------------------------------------------------- // Modifying // ---------------------------------------------------------------------------- /** * Delegates to the {@link IndexerEngine} to update artifact to the index */ public void addArtifactToIndex( ArtifactContext ac, IndexingContext context ) throws IOException { indexer.addArtifactsToIndex( Collections.singleton( ac ), context ); } public void addArtifactsToIndex( Collection<ArtifactContext> acs, IndexingContext context ) throws IOException { indexer.addArtifactsToIndex( acs, context ); } /** * Delegates to the {@link IndexerEngine} to remove artifact from the index */ public void deleteArtifactFromIndex( ArtifactContext ac, IndexingContext context ) throws IOException { indexer.deleteArtifactsFromIndex( Collections.singleton( ac ), context ); } public void deleteArtifactsFromIndex( Collection<ArtifactContext> acs, IndexingContext context ) throws IOException { indexer.deleteArtifactsFromIndex( acs, context ); } // ---------------------------------------------------------------------------- // Searching // ---------------------------------------------------------------------------- public FlatSearchResponse searchFlat( FlatSearchRequest request ) throws IOException { if ( request.getContexts().isEmpty() ) { request.getContexts().addAll( getIndexingContexts().values() ); } return indexer.searchFlat( request ); } public IteratorSearchResponse searchIterator( IteratorSearchRequest request ) throws IOException { if ( request.getContexts().isEmpty() ) { request.getContexts().addAll( getIndexingContexts().values() ); } return indexer.searchIterator( request ); } public GroupedSearchResponse searchGrouped( GroupedSearchRequest request ) throws IOException { if ( request.getContexts().isEmpty() ) { request.getContexts().addAll( getIndexingContexts().values() ); } return indexer.searchGrouped( request ); } // ---------------------------------------------------------------------------- // Query construction // ---------------------------------------------------------------------------- @Deprecated public Query constructQuery( Field field, String query, SearchType type ) throws IllegalArgumentException { try { return queryCreator.constructQuery( field, query, type ); } catch ( ParseException e ) { throw new IllegalArgumentException( e ); } } public Query constructQuery( Field field, SearchExpression expression ) throws IllegalArgumentException { return indexer.constructQuery( field, expression ); } // ---------------------------------------------------------------------------- // Identification // ---------------------------------------------------------------------------- public Collection<ArtifactInfo> identify( Field field, String query ) throws IllegalArgumentException, IOException { return identify( constructQuery( field, query, SearchType.EXACT ) ); } public Collection<ArtifactInfo> identify( File artifact ) throws IOException { return identify( artifact, indexingContexts.values() ); } public Collection<ArtifactInfo> identify( File artifact, Collection<IndexingContext> contexts ) throws IOException { return indexer.identify( artifact, contexts ); } public Collection<ArtifactInfo> identify( Query query ) throws IOException { return identify( query, indexingContexts.values() ); } public Collection<ArtifactInfo> identify( Query query, Collection<IndexingContext> contexts ) throws IOException { return indexer.identify( query, contexts ); } }