Sfoglia il codice sorgente

Migrating repository scanner to java.nio

pull/46/head
Martin Stockhammer 6 anni fa
parent
commit
9148a900ee

+ 27
- 29
archiva-modules/archiva-base/archiva-repository-scanner/src/main/java/org/apache/archiva/repository/scanner/DefaultRepositoryScanner.java Vedi File



import org.apache.archiva.admin.model.RepositoryAdminException; import org.apache.archiva.admin.model.RepositoryAdminException;
import org.apache.archiva.admin.model.beans.ManagedRepository; import org.apache.archiva.admin.model.beans.ManagedRepository;
import org.apache.archiva.configuration.ArchivaConfiguration;
import org.apache.archiva.configuration.FileTypes; import org.apache.archiva.configuration.FileTypes;
import org.apache.archiva.consumers.InvalidRepositoryContentConsumer; import org.apache.archiva.consumers.InvalidRepositoryContentConsumer;
import org.apache.archiva.consumers.KnownRepositoryContentConsumer; import org.apache.archiva.consumers.KnownRepositoryContentConsumer;
import org.apache.archiva.consumers.RepositoryContentConsumer; import org.apache.archiva.consumers.RepositoryContentConsumer;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.codehaus.plexus.util.DirectoryWalker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;


import javax.inject.Inject; import javax.inject.Inject;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.io.IOException;
import java.nio.file.FileVisitOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;


/** /**
* DefaultRepositoryScanner * DefaultRepositoryScanner
public class DefaultRepositoryScanner public class DefaultRepositoryScanner
implements RepositoryScanner implements RepositoryScanner
{ {

private static final Logger log = LoggerFactory.getLogger(DefaultRepositoryScanner.class);

@Inject @Inject
private FileTypes filetypes; private FileTypes filetypes;


throw new IllegalArgumentException( "Unable to operate on a null repository." ); throw new IllegalArgumentException( "Unable to operate on a null repository." );
} }


File repositoryBase = new File( repository.getLocation() );
Path repositoryBase = Paths.get( repository.getLocation() );


//MRM-1342 Repository statistics report doesn't appear to be working correctly //MRM-1342 Repository statistics report doesn't appear to be working correctly
//create the repo if not existing to have an empty stats //create the repo if not existing to have an empty stats
if ( !repositoryBase.exists() && !repositoryBase.mkdirs() )
if ( !Files.exists(repositoryBase))
{ {
throw new UnsupportedOperationException(
"Unable to scan a repository, directory " + repositoryBase.getPath() + " does not exist." );
try {
Files.createDirectories(repositoryBase);
} catch (IOException e) {
throw new UnsupportedOperationException("Unable to scan a repository, directory " + repositoryBase + " does not exist." );
}
} }


if ( !repositoryBase.isDirectory() )
if ( !Files.isDirectory(repositoryBase) )
{ {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
"Unable to scan a repository, path " + repositoryBase.getPath() + " is not a directory." );
"Unable to scan a repository, path " + repositoryBase+ " is not a directory." );
} }


// Setup Includes / Excludes. // Setup Includes / Excludes.
// Scan All Content. (intentional) // Scan All Content. (intentional)
allIncludes.add( "**/*" ); allIncludes.add( "**/*" );


// Setup Directory Walker
DirectoryWalker dirWalker = new DirectoryWalker();

dirWalker.setBaseDir( repositoryBase );

dirWalker.setIncludes( allIncludes );
dirWalker.setExcludes( allExcludes );

// Setup the Scan Instance // Setup the Scan Instance
RepositoryScannerInstance scannerInstance = RepositoryScannerInstance scannerInstance =
new RepositoryScannerInstance( repository, knownContentConsumers, invalidContentConsumers, changesSince ); new RepositoryScannerInstance( repository, knownContentConsumers, invalidContentConsumers, changesSince );


scannerInstance.setFileNameIncludePattern(allIncludes);
scannerInstance.setFileNameExcludePattern(allExcludes);
inProgressScans.add( scannerInstance ); inProgressScans.add( scannerInstance );


RepositoryScanStatistics stats;
RepositoryScanStatistics stats = null;
try try
{ {
dirWalker.addDirectoryWalkListener( scannerInstance );

// Execute scan.
dirWalker.scan();
Files.walkFileTree(repositoryBase, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, scannerInstance);


stats = scannerInstance.getStatistics(); stats = scannerInstance.getStatistics();


stats.setKnownConsumers( gatherIds( knownContentConsumers ) ); stats.setKnownConsumers( gatherIds( knownContentConsumers ) );
stats.setInvalidConsumers( gatherIds( invalidContentConsumers ) ); stats.setInvalidConsumers( gatherIds( invalidContentConsumers ) );
}
finally
} catch (IOException e) {
log.error("Could not scan directory {}", repositoryBase);
} finally
{ {
inProgressScans.remove( scannerInstance ); inProgressScans.remove( scannerInstance );
} }

+ 4
- 8
archiva-modules/archiva-base/archiva-repository-scanner/src/main/java/org/apache/archiva/repository/scanner/RepositoryContentConsumers.java Vedi File

import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;


import javax.inject.Inject; import javax.inject.Inject;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.nio.file.Path;
import java.util.*;


/** /**
* RepositoryContentConsumerUtil * RepositoryContentConsumerUtil
* @param localFile the local file to execute the consumers against. * @param localFile the local file to execute the consumers against.
* @param updateRelatedArtifacts TODO * @param updateRelatedArtifacts TODO
*/ */
public void executeConsumers( ManagedRepository repository, File localFile, boolean updateRelatedArtifacts )
public void executeConsumers(ManagedRepository repository, Path localFile, boolean updateRelatedArtifacts )
throws RepositoryAdminException throws RepositoryAdminException
{ {
List<KnownRepositoryContentConsumer> selectedKnownConsumers = null; List<KnownRepositoryContentConsumer> selectedKnownConsumers = null;


// yuck. In case you can't read this, it says // yuck. In case you can't read this, it says
// "process the file if the consumer has it in the includes list, and not in the excludes list" // "process the file if the consumer has it in the includes list, and not in the excludes list"
BaseFile baseFile = new BaseFile( repository.getLocation(), localFile );
BaseFile baseFile = new BaseFile( repository.getLocation(), localFile.toFile() );
ConsumerWantsFilePredicate predicate = new ConsumerWantsFilePredicate( repository ); ConsumerWantsFilePredicate predicate = new ConsumerWantsFilePredicate( repository );
predicate.setBasefile( baseFile ); predicate.setBasefile( baseFile );
predicate.setCaseSensitive( false ); predicate.setCaseSensitive( false );

+ 118
- 54
archiva-modules/archiva-base/archiva-repository-scanner/src/main/java/org/apache/archiva/repository/scanner/RepositoryScannerInstance.java Vedi File

import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.functors.IfClosure; import org.apache.commons.collections.functors.IfClosure;
import org.apache.commons.lang.SystemUtils; import org.apache.commons.lang.SystemUtils;
import org.codehaus.plexus.util.DirectoryWalkListener;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;


import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.stream.Collectors;


/** /**
* RepositoryScannerInstance * RepositoryScannerInstance
*/ */
public class RepositoryScannerInstance public class RepositoryScannerInstance
implements DirectoryWalkListener
implements FileVisitor<Path>
{ {
private Logger log = LoggerFactory.getLogger( RepositoryScannerInstance.class ); private Logger log = LoggerFactory.getLogger( RepositoryScannerInstance.class );




private Map<String, Long> consumerCounts; private Map<String, Long> consumerCounts;



private List<String> fileNameIncludePattern = new ArrayList<>();
private List<String> fileNameExcludePattern = new ArrayList<>();

private List<PathMatcher> includeMatcher = new ArrayList<>();
private List<PathMatcher> excludeMatcher = new ArrayList<>();

private boolean isRunning = false;

Path basePath = null;

public RepositoryScannerInstance( ManagedRepository repository, public RepositoryScannerInstance( ManagedRepository repository,
List<KnownRepositoryContentConsumer> knownConsumerList, List<KnownRepositoryContentConsumer> knownConsumerList,
List<InvalidRepositoryContentConsumer> invalidConsumerList ) List<InvalidRepositoryContentConsumer> invalidConsumerList )
this.knownConsumers = knownConsumerList; this.knownConsumers = knownConsumerList;
this.invalidConsumers = invalidConsumerList; this.invalidConsumers = invalidConsumerList;


addFileNameIncludePattern("**/*");

consumerTimings = new HashMap<>(); consumerTimings = new HashMap<>();
consumerCounts = new HashMap<>(); consumerCounts = new HashMap<>();


return consumerCounts; return consumerCounts;
} }


@Override
public void directoryWalkStarting( File basedir )
public ManagedRepository getRepository()
{ {
log.info( "Walk Started: [{}] {}", this.repository.getId(), this.repository.getLocation() );
stats.triggerStart();
return repository;
} }


@Override
public void directoryWalkStep( int percentage, File file )
public RepositoryScanStatistics getStats()
{
return stats;
}

public long getChangesSince()
{ {
log.debug( "Walk Step: {}, {}", percentage, file );
return changesSince;
}


stats.increaseFileCount();
public List<String> getFileNameIncludePattern() {
return fileNameIncludePattern;
}


// consume files regardless - the predicate will check the timestamp
BaseFile basefile = new BaseFile( repository.getLocation(), file );
public void setFileNameIncludePattern(List<String> fileNamePattern) {
this.fileNameIncludePattern = fileNamePattern;
FileSystem sys = FileSystems.getDefault();
this.includeMatcher = fileNamePattern.stream().map(ts ->sys
.getPathMatcher("glob:" + ts)).collect(Collectors.toList());
}


// Timestamp finished points to the last successful scan, not this current one.
if ( file.lastModified() >= changesSince )
{
stats.increaseNewFileCount();
public void addFileNameIncludePattern(String fileNamePattern) {
if (! this.fileNameIncludePattern.contains(fileNamePattern)) {
this.fileNameIncludePattern.add(fileNamePattern);
this.includeMatcher.add(FileSystems.getDefault().getPathMatcher("glob:" + fileNamePattern));
} }
}


consumerProcessFile.setBasefile( basefile );
consumerWantsFile.setBasefile( basefile );
public List<String> getFileNameExcludePattern() {
return fileNameExcludePattern;
}


Closure processIfWanted = IfClosure.getInstance( consumerWantsFile, consumerProcessFile );
CollectionUtils.forAllDo( this.knownConsumers, processIfWanted );
public void setFileNameExcludePattern(List<String> fileNamePattern) {
this.fileNameExcludePattern = fileNamePattern;
FileSystem sys = FileSystems.getDefault();
this.excludeMatcher = fileNamePattern.stream().map(ts ->sys
.getPathMatcher("glob:" + ts)).collect(Collectors.toList());
}


if ( consumerWantsFile.getWantedFileCount() <= 0 )
{
// Nothing known processed this file. It is invalid!
CollectionUtils.forAllDo( this.invalidConsumers, consumerProcessFile );
public void addFileNameExcludePattern(String fileNamePattern) {
if (! this.fileNameExcludePattern.contains(fileNamePattern)) {
this.fileNameExcludePattern.add(fileNamePattern);
this.excludeMatcher.add(FileSystems.getDefault().getPathMatcher("glob:" + fileNamePattern));
} }
} }



@Override @Override
public void directoryWalkFinished()
{
TriggerScanCompletedClosure scanCompletedClosure = new TriggerScanCompletedClosure( repository, true );
CollectionUtils.forAllDo( knownConsumers, scanCompletedClosure );
CollectionUtils.forAllDo( invalidConsumers, scanCompletedClosure );
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
if (!isRunning) {
isRunning = true;
this.basePath = dir;
log.info( "Walk Started: [{}] {}", this.repository.getId(), this.repository.getLocation() );
stats.triggerStart();
}
return FileVisitResult.CONTINUE;
}


stats.setConsumerTimings( consumerTimings );
stats.setConsumerCounts( consumerCounts );
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (excludeMatcher.stream().noneMatch(m -> m.matches(file)) && includeMatcher.stream().allMatch(m -> m.matches(file))) {
log.debug( "Walk Step: {}, {}", file );


log.info( "Walk Finished: [{}] {}", this.repository.getId(), this.repository.getLocation() );
stats.triggerFinished();
stats.increaseFileCount();

// consume files regardless - the predicate will check the timestamp
BaseFile basefile = new BaseFile( repository.getLocation(), file.toFile() );

// Timestamp finished points to the last successful scan, not this current one.
if ( Files.getLastModifiedTime(file).toMillis() >= changesSince )
{
stats.increaseNewFileCount();
}

consumerProcessFile.setBasefile( basefile );
consumerWantsFile.setBasefile( basefile );

Closure processIfWanted = IfClosure.getInstance( consumerWantsFile, consumerProcessFile );
CollectionUtils.forAllDo( this.knownConsumers, processIfWanted );

if ( consumerWantsFile.getWantedFileCount() <= 0 )
{
// Nothing known processed this file. It is invalid!
CollectionUtils.forAllDo( this.invalidConsumers, consumerProcessFile );
}

}
return FileVisitResult.CONTINUE;
} }


/**
* Debug method from DirectoryWalker.
*/
@Override @Override
public void debug( String message )
{
log.debug( "Repository Scanner: {}", message );
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
log.error("Error occured at {}: {}", file, exc.getMessage(), exc);
if (basePath!=null && Files.isSameFile(file, basePath)) {
finishWalk();
}
return FileVisitResult.CONTINUE;
} }


public ManagedRepository getRepository()
{
return repository;
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if (Files.isSameFile(dir, basePath)) {
finishWalk();
}
return FileVisitResult.CONTINUE;
} }


public RepositoryScanStatistics getStats()
{
return stats;
}
private void finishWalk() {
this.isRunning = false;
TriggerScanCompletedClosure scanCompletedClosure = new TriggerScanCompletedClosure( repository, true );
CollectionUtils.forAllDo( knownConsumers, scanCompletedClosure );
CollectionUtils.forAllDo( invalidConsumers, scanCompletedClosure );


public long getChangesSince()
{
return changesSince;
stats.setConsumerTimings( consumerTimings );
stats.setConsumerCounts( consumerCounts );

log.info( "Walk Finished: [{}] {}", this.repository.getId(), this.repository.getLocation() );
stats.triggerFinished();
this.basePath = null;
} }
} }

+ 8
- 7
archiva-modules/archiva-base/archiva-repository-scanner/src/test/java/org/apache/archiva/repository/scanner/RepositoryContentConsumersTest.java Vedi File

import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;


import javax.inject.Inject; import javax.inject.Inject;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
@Inject @Inject
ApplicationContext applicationContext; ApplicationContext applicationContext;


protected ManagedRepository createRepository( String id, String name, File location )
protected ManagedRepository createRepository( String id, String name, Path location )
{ {
ManagedRepository repo = new ManagedRepository(); ManagedRepository repo = new ManagedRepository();
repo.setId( id ); repo.setId( id );
repo.setName( name ); repo.setName( name );
repo.setLocation( location.getAbsolutePath() );
repo.setLocation( location.toAbsolutePath().toString() );
return repo; return repo;
} }




consumers.setSelectedInvalidConsumers( Collections.singletonList( selectedInvalidConsumer ) ); consumers.setSelectedInvalidConsumers( Collections.singletonList( selectedInvalidConsumer ) );


ManagedRepository repo = createRepository( "id", "name", new File( "target/test-repo" ) );
File testFile = new File( "target/test-repo/path/to/test-file.txt" );
ManagedRepository repo = createRepository( "id", "name", Paths.get( "target/test-repo" ) );
Path testFile = Paths.get( "target/test-repo/path/to/test-file.txt" );


Date startTime = new Date( System.currentTimeMillis() ); Date startTime = new Date( System.currentTimeMillis() );
startTime.setTime( 12345678 ); startTime.setTime( 12345678 );
knownControl.reset(); knownControl.reset();
invalidControl.reset(); invalidControl.reset();


File notIncludedTestFile = new File( "target/test-repo/path/to/test-file.xml" );
Path notIncludedTestFile = Paths.get( "target/test-repo/path/to/test-file.xml" );


selectedKnownConsumer.beginScan( repo, startTime, false ); selectedKnownConsumer.beginScan( repo, startTime, false );
expect( selectedKnownConsumer.getExcludes() ).andReturn( Collections.<String>emptyList() ); expect( selectedKnownConsumer.getExcludes() ).andReturn( Collections.<String>emptyList() );
knownControl.reset(); knownControl.reset();
invalidControl.reset(); invalidControl.reset();


File excludedTestFile = new File( "target/test-repo/path/to/test-file.txt" );
Path excludedTestFile = Paths.get( "target/test-repo/path/to/test-file.txt" );


selectedKnownConsumer.beginScan( repo, startTime, false ); selectedKnownConsumer.beginScan( repo, startTime, false );
expect( selectedKnownConsumer.getExcludes() ).andReturn( Collections.singletonList( "**/test-file.txt" ) ); expect( selectedKnownConsumer.getExcludes() ).andReturn( Collections.singletonList( "**/test-file.txt" ) );

+ 17
- 15
archiva-modules/archiva-base/archiva-repository-scanner/src/test/java/org/apache/archiva/repository/scanner/RepositoryScannerTest.java Vedi File

import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;


import javax.inject.Inject; import javax.inject.Inject;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
@Inject @Inject
ApplicationContext applicationContext; ApplicationContext applicationContext;


protected ManagedRepository createRepository( String id, String name, File location )
protected ManagedRepository createRepository( String id, String name, Path location )
{ {
ManagedRepository repo = new ManagedRepository(); ManagedRepository repo = new ManagedRepository();
repo.setId( id ); repo.setId( id );
repo.setName( name ); repo.setName( name );
repo.setLocation( location.getAbsolutePath() );
repo.setLocation( location.toAbsolutePath().toString());
return repo; return repo;
} }




private ManagedRepository createDefaultRepository() private ManagedRepository createDefaultRepository()
{ {
File repoDir =
Paths.get( System.getProperty( "basedir" ), "src/test/repositories/default-repository" ).toFile();
Path repoDir =
Paths.get( System.getProperty( "basedir" ), "src/test/repositories/default-repository" );


assertTrue( "Default Test Repository should exist.", repoDir.exists() && repoDir.isDirectory() );
assertTrue( "Default Test Repository should exist.", Files.exists(repoDir) && Files.isDirectory(repoDir) );


return createRepository( "testDefaultRepo", "Test Default Repository", repoDir ); return createRepository( "testDefaultRepo", "Test Default Repository", repoDir );
} }
private ManagedRepository createSimpleRepository() private ManagedRepository createSimpleRepository()
throws IOException, ParseException throws IOException, ParseException
{ {
File srcDir = Paths.get( System.getProperty( "basedir" ), "src/test/repositories/simple-repository" ).toFile();
Path srcDir = Paths.get( System.getProperty( "basedir" ), "src/test/repositories/simple-repository" );


File repoDir = Paths.get( System.getProperty( "basedir" ), "target/test-repos/simple-repository" ).toFile();
Path repoDir = Paths.get( System.getProperty( "basedir" ), "target/test-repos/simple-repository" );


FileUtils.deleteDirectory( repoDir );
org.apache.archiva.common.utils.FileUtils.deleteDirectory( repoDir );


FileUtils.copyDirectory( srcDir, repoDir );
FileUtils.copyDirectory( srcDir.toFile(), repoDir.toFile() );


File repoFile = new File( repoDir,
Path repoFile = repoDir.resolve(
"groupId/snapshot-artifact/1.0-alpha-1-SNAPSHOT/snapshot-artifact-1.0-alpha-1-20050611.202024-1.pom" ); "groupId/snapshot-artifact/1.0-alpha-1-SNAPSHOT/snapshot-artifact-1.0-alpha-1-20050611.202024-1.pom" );
repoFile.setLastModified( getTimestampAsMillis( "20050611.202024" ) );
Files.setLastModifiedTime(repoFile, FileTime.fromMillis(getTimestampAsMillis( "20050611.202024" ) ));


assertTrue( "Simple Test Repository should exist.", repoDir.exists() && repoDir.isDirectory() );
assertTrue( "Simple Test Repository should exist.", Files.exists(repoDir) && Files.isDirectory(repoDir) );


return createRepository( "testSimpleRepo", "Test Simple Repository", repoDir ); return createRepository( "testSimpleRepo", "Test Simple Repository", repoDir );
} }


private ManagedRepository createLegacyRepository() private ManagedRepository createLegacyRepository()
{ {
File repoDir = Paths.get( System.getProperty( "basedir" ), "src/test/repositories/legacy-repository" ).toFile();
Path repoDir = Paths.get( System.getProperty( "basedir" ), "src/test/repositories/legacy-repository" );


assertTrue( "Legacy Test Repository should exist.", repoDir.exists() && repoDir.isDirectory() );
assertTrue( "Legacy Test Repository should exist.", Files.exists(repoDir) && Files.isDirectory(repoDir) );


ManagedRepository repo = createRepository( "testLegacyRepo", "Test Legacy Repository", repoDir ); ManagedRepository repo = createRepository( "testLegacyRepo", "Test Legacy Repository", repoDir );
repo.setLayout( "legacy" ); repo.setLayout( "legacy" );

+ 1
- 1
archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/main/java/org/apache/archiva/scheduler/repository/ArchivaRepositoryScanningTaskExecutor.java Vedi File

if ( task.getResourceFile() != null ) if ( task.getResourceFile() != null )
{ {
log.debug( "Executing task from queue with job name: {}", task ); log.debug( "Executing task from queue with job name: {}", task );
consumers.executeConsumers( arepo, task.getResourceFile(), task.isUpdateRelatedArtifacts() );
consumers.executeConsumers( arepo, task.getResourceFile().toPath(), task.isUpdateRelatedArtifacts() );
} }
else else
{ {

Loading…
Annulla
Salva