blob: bfda57d6ce4bf546fbad634fcc7bd950493f8d8f [file] [log] [blame]
/*
* 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);
}
}