| /* |
| * 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. |
| */ |
| package org.apache.maven.index; |
| |
| import javax.inject.Inject; |
| import javax.inject.Named; |
| import javax.inject.Singleton; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.nio.file.Files; |
| 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<>(); |
| |
| @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 tmpDir = Files.createTempDirectory(context.getId() + "-tmp").toFile(); |
| 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 new IOException("Error scanning context " + context.getId() + ": " + ex, ex); |
| } finally { |
| if (tmpContext != null) { |
| tmpContext.close(true); |
| } |
| |
| 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); |
| } |
| } |