blob: e88fac68bcfcb3dff57a86f7359170b698ebc389 [file] [log] [blame]
package org.apache.archiva.scheduler.indexing.maven;
/*
* 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 Li
* cense 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 org.apache.archiva.indexer.ArchivaIndexingContext;
import org.apache.archiva.indexer.UnsupportedBaseContextException;
import org.apache.archiva.components.taskqueue.Task;
import org.apache.archiva.components.taskqueue.execution.TaskExecutionException;
import org.apache.archiva.components.taskqueue.execution.TaskExecutor;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.features.IndexCreationFeature;
import org.apache.archiva.scheduler.indexing.ArtifactIndexingTask;
import org.apache.maven.index.ArtifactContext;
import org.apache.maven.index.ArtifactContextProducer;
import org.apache.maven.index.DefaultScannerListener;
import org.apache.maven.index.FlatSearchRequest;
import org.apache.maven.index.FlatSearchResponse;
import org.apache.maven.index.Indexer;
import org.apache.maven.index.IndexerEngine;
import org.apache.maven.index.MAVEN;
import org.apache.maven.index.Scanner;
import org.apache.maven.index.ScanningRequest;
import org.apache.maven.index.ScanningResult;
import org.apache.maven.index.context.IndexingContext;
import org.apache.maven.index.expr.SourcedSearchExpression;
import org.apache.maven.index.packer.IndexPacker;
import org.apache.maven.index.packer.IndexPackingRequest;
import org.apache.maven.index_shaded.lucene.search.BooleanClause;
import org.apache.maven.index_shaded.lucene.search.BooleanQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.inject.Inject;
import java.io.IOException;
import java.nio.file.Path;
/**
* ArchivaIndexingTaskExecutor Executes all indexing tasks. Adding, updating and removing artifacts from the index are
* all performed by this executor. Add and update artifact in index tasks are added in the indexing task queue by the
* NexusIndexerConsumer while remove artifact from index tasks are added by the LuceneCleanupRemoveIndexedConsumer.
*/
@Service( "taskExecutor#indexing" )
public class ArchivaIndexingTaskExecutor
implements TaskExecutor
{
private Logger log = LoggerFactory.getLogger( ArchivaIndexingTaskExecutor.class );
@Inject
private IndexPacker indexPacker;
@Inject
private ArtifactContextProducer artifactContextProducer;
@Inject
private Indexer indexer;
@Inject
private Scanner scanner;
@Inject
IndexerEngine indexerEngine;
/**
* depending on current {@link Task} you have.
* If {@link org.apache.archiva.scheduler.indexing.ArtifactIndexingTask.Action#FINISH} && isExecuteOnEntireRepo:
* repository will be scanned.
*
* @param task
* @throws TaskExecutionException
*/
@Override
public void executeTask( Task task )
throws TaskExecutionException
{
ArtifactIndexingTask indexingTask = (ArtifactIndexingTask) task;
ManagedRepository repository = indexingTask.getRepository( );
ArchivaIndexingContext archivaContext = indexingTask.getContext( );
IndexingContext context = null;
try
{
context = archivaContext.getBaseContext( IndexingContext.class );
}
catch ( UnsupportedBaseContextException e )
{
throw new TaskExecutionException( "Bad repository type.", e );
}
if ( ArtifactIndexingTask.Action.FINISH.equals( indexingTask.getAction( ) )
&& indexingTask.isExecuteOnEntireRepo( ) )
{
long start = System.currentTimeMillis( );
try
{
context.updateTimestamp( );
DefaultScannerListener listener = new DefaultScannerListener( context, indexerEngine, true, null );
ScanningRequest request = new ScanningRequest( context, listener );
ScanningResult result = scanner.scan( request );
if ( result.hasExceptions( ) )
{
log.error( "Exceptions occured during index scan of " + context.getId( ) );
result.getExceptions( ).stream( ).map( e -> e.getMessage( ) ).distinct( ).limit( 5 ).forEach(
s -> log.error( "Message: " + s )
);
}
}
catch ( IOException e )
{
log.error( "Error during context scan {}: {}", context.getId( ), context.getIndexDirectory( ) );
}
long end = System.currentTimeMillis( );
log.info( "indexed maven repository: {}, onlyUpdate: {}, time {} ms", repository.getId( ),
indexingTask.isOnlyUpdate( ), ( end - start ) );
log.debug( "Finishing indexing task on repo: {}", repository.getId( ) );
finishIndexingTask( indexingTask, repository, context );
}
else
{
// create context if not a repo scan request
if ( !indexingTask.isExecuteOnEntireRepo( ) )
{
try
{
log.debug( "Creating indexing context on resource: {}", //
( indexingTask.getResourceFile( ) == null
? "none"
: indexingTask.getResourceFile( ) ) );
archivaContext = repository.getIndexingContext( );
context = archivaContext.getBaseContext( IndexingContext.class );
}
catch ( UnsupportedBaseContextException e )
{
log.error( "Error occurred while creating context: {}", e.getMessage( ) );
throw new TaskExecutionException( "Error occurred while creating context: " + e.getMessage( ), e );
}
}
if ( context == null || context.getIndexDirectory( ) == null )
{
throw new TaskExecutionException( "Trying to index an artifact but the context is already closed" );
}
try
{
Path artifactFile = indexingTask.getResourceFile( );
if ( artifactFile == null )
{
log.debug( "no artifact pass in indexing task so skip it" );
}
else
{
ArtifactContext ac = artifactContextProducer.getArtifactContext( context, artifactFile.toFile( ) );
if ( ac != null )
{
// MRM-1779 pom must be indexed too
// TODO make that configurable?
if ( artifactFile.getFileName( ).toString( ).endsWith( ".pom" ) )
{
ac.getArtifactInfo( ).setFileExtension( "pom" );
ac.getArtifactInfo( ).setPackaging( "pom" );
ac.getArtifactInfo( ).setClassifier( "pom" );
}
if ( indexingTask.getAction( ).equals( ArtifactIndexingTask.Action.ADD ) )
{
//IndexSearcher s = context.getIndexSearcher();
//String uinfo = ac.getArtifactInfo().getUinfo();
//TopDocs d = s.search( new TermQuery( new Term( ArtifactInfo.UINFO, uinfo ) ), 1 );
BooleanQuery.Builder qb = new BooleanQuery.Builder();
qb.add( indexer.constructQuery( MAVEN.GROUP_ID, new SourcedSearchExpression(
ac.getArtifactInfo( ).getGroupId( ) ) ), BooleanClause.Occur.MUST );
qb.add( indexer.constructQuery( MAVEN.ARTIFACT_ID, new SourcedSearchExpression(
ac.getArtifactInfo( ).getArtifactId( ) ) ), BooleanClause.Occur.MUST );
qb.add( indexer.constructQuery( MAVEN.VERSION, new SourcedSearchExpression(
ac.getArtifactInfo( ).getVersion( ) ) ), BooleanClause.Occur.MUST );
if ( ac.getArtifactInfo( ).getClassifier( ) != null )
{
qb.add( indexer.constructQuery( MAVEN.CLASSIFIER, new SourcedSearchExpression(
ac.getArtifactInfo( ).getClassifier( ) ) ), BooleanClause.Occur.MUST );
}
if ( ac.getArtifactInfo( ).getPackaging( ) != null )
{
qb.add( indexer.constructQuery( MAVEN.PACKAGING, new SourcedSearchExpression(
ac.getArtifactInfo( ).getPackaging( ) ) ), BooleanClause.Occur.MUST );
}
FlatSearchRequest flatSearchRequest = new FlatSearchRequest( qb.build(), context );
FlatSearchResponse flatSearchResponse = indexer.searchFlat( flatSearchRequest );
if ( flatSearchResponse.getResults( ).isEmpty( ) )
{
log.debug( "Adding artifact '{}' to index..", ac.getArtifactInfo( ) );
indexerEngine.index( context, ac );
}
else
{
log.debug( "Updating artifact '{}' in index..", ac.getArtifactInfo( ) );
// TODO check if update exists !!
indexerEngine.update( context, ac );
}
context.updateTimestamp( );
context.commit( );
}
else
{
log.debug( "Removing artifact '{}' from index..", ac.getArtifactInfo( ) );
indexerEngine.remove( context, ac );
}
}
}
// close the context if not a repo scan request
if ( !indexingTask.isExecuteOnEntireRepo( ) )
{
log.debug( "Finishing indexing task on resource file : {}", indexingTask.getResourceFile( ) != null
? indexingTask.getResourceFile( )
: " none " );
finishIndexingTask( indexingTask, repository, context );
}
}
catch ( IOException e )
{
log.error( "Error occurred while executing indexing task '{}': {}", indexingTask, e.getMessage( ),
e );
throw new TaskExecutionException( "Error occurred while executing indexing task '" + indexingTask + "'",
e );
}
}
}
private void finishIndexingTask( ArtifactIndexingTask indexingTask, ManagedRepository repository,
IndexingContext context )
throws TaskExecutionException
{
try
{
log.debug( "Finishing indexing" );
context.optimize( );
if ( repository.supportsFeature( IndexCreationFeature.class ) )
{
IndexCreationFeature icf = repository.getFeature( IndexCreationFeature.class ).get( );
if ( !icf.isSkipPackedIndexCreation( ) && icf.getLocalPackedIndexPath( ) != null && icf.getLocalIndexPath().getFilePath()!=null )
{
log.debug( "Creating packed index from {} on {}", context.getIndexDirectoryFile( ), icf.getLocalPackedIndexPath( ) );
IndexPackingRequest request = new IndexPackingRequest( context, //
context.acquireIndexSearcher( ).getIndexReader( ),
//
icf.getLocalPackedIndexPath( ).getFilePath().toFile( ) );
indexPacker.packIndex( request );
context.updateTimestamp( true );
log.debug( "Index file packed at '{}'.", icf.getLocalPackedIndexPath( ) );
}
else
{
log.debug( "skip packed index creation" );
}
}
else
{
log.debug( "skip packed index creation" );
}
}
catch ( IOException e )
{
log.error( "Error occurred while executing indexing task '{}': {}", indexingTask, e.getMessage( ) );
throw new TaskExecutionException( "Error occurred while executing indexing task '" + indexingTask + "'",
e );
}
}
public void setIndexPacker( IndexPacker indexPacker )
{
this.indexPacker = indexPacker;
}
}