Improving repository API

This commit is contained in:
Martin Stockhammer 2020-06-11 14:33:00 +02:00
parent b942314aa2
commit 46fd585f40
15 changed files with 477 additions and 185 deletions

View File

@ -194,4 +194,6 @@ public class VersionUtil
}
return version;
}
}

View File

@ -23,9 +23,9 @@ import org.apache.archiva.common.utils.VersionComparator;
import org.apache.archiva.common.utils.VersionUtil;
import org.apache.archiva.metadata.audit.RepositoryListener;
import org.apache.archiva.metadata.repository.RepositorySession;
import org.apache.archiva.repository.ManagedRepositoryContent;
import org.apache.archiva.repository.LayoutException;
import org.apache.archiva.repository.BaseRepositoryContentLayout;
import org.apache.archiva.repository.LayoutException;
import org.apache.archiva.repository.ManagedRepositoryContent;
import org.apache.archiva.repository.content.Artifact;
import org.apache.archiva.repository.content.ContentItem;
import org.apache.archiva.repository.content.base.ArchivaItemSelector;
@ -74,94 +74,94 @@ public class DaysOldRepositoryPurge
{
ContentItem item = repository.toItem( path );
if ( item instanceof Artifact )
Artifact artifactItem = repository.getLayout( BaseRepositoryContentLayout.class ).adaptItem( Artifact.class, item );
if ( !artifactItem.exists( ) )
{
Artifact artifactItem = (Artifact) item;
if ( !artifactItem.exists( ) )
{
return;
}
// ArtifactReference artifact = repository.toArtifactReference( path );
Calendar olderThanThisDate = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
olderThanThisDate.add( Calendar.DATE, -retentionPeriod );
ArchivaItemSelector selector = ArchivaItemSelector.builder( )
.withNamespace( artifactItem.getVersion( ).getProject( ).getNamespace( ).getId( ) )
.withProjectId( artifactItem.getVersion( ).getProject( ).getId( ) )
.withVersion( artifactItem.getVersion( ).getId( ) )
.withClassifier( "*" )
.includeRelatedArtifacts( )
.build( );
List<String> artifactVersions;
try( Stream<? extends Artifact> stream = repository.getLayout( BaseRepositoryContentLayout.class ).newArtifactStream( selector )){
artifactVersions = stream.map( a -> a.getArtifactVersion( ) )
.filter( StringUtils::isNotEmpty )
.distinct()
.collect( Collectors.toList( ) );
}
Collections.sort( artifactVersions, VersionComparator.getInstance( ) );
if ( retentionCount > artifactVersions.size( ) )
{
// Done. nothing to do here. skip it.
return;
}
int countToPurge = artifactVersions.size( ) - retentionCount;
ArchivaItemSelector.Builder artifactSelectorBuilder = ArchivaItemSelector.builder( )
.withNamespace( artifactItem.getVersion( ).getProject( ).getNamespace( ).getId( ) )
.withProjectId( artifactItem.getVersion( ).getProject( ).getId( ) )
.withVersion( artifactItem.getVersion( ).getId( ) )
.withArtifactId( artifactItem.getId() )
.withClassifier( "*" )
.includeRelatedArtifacts( );
Set<Artifact> artifactsToDelete = new HashSet<>( );
for ( String version : artifactVersions )
{
if ( countToPurge-- <= 0 )
{
break;
}
ArchivaItemSelector artifactSelector = artifactSelectorBuilder.withArtifactVersion( version ).build( );
try
{
// Is this a generic snapshot "1.0-SNAPSHOT" ?
if ( VersionUtil.isGenericSnapshot( version ) )
{
List<? extends Artifact> artifactList = repository.getLayout( BaseRepositoryContentLayout.class ).getArtifacts( artifactSelector );
if ( artifactList.size()>0 && artifactList.get(0).getAsset().getModificationTime( ).toEpochMilli( ) < olderThanThisDate.getTimeInMillis( ) )
{
artifactsToDelete.addAll( artifactList );
}
}
// Is this a timestamp snapshot "1.0-20070822.123456-42" ?
else if ( VersionUtil.isUniqueSnapshot( version ) )
{
Calendar timestampCal = uniqueSnapshotToCalendar( version );
if ( timestampCal.getTimeInMillis( ) < olderThanThisDate.getTimeInMillis( ) )
{
artifactsToDelete.addAll( repository.getLayout( BaseRepositoryContentLayout.class ).getArtifacts( artifactSelector ) );
}
}
} catch ( IllegalArgumentException e ) {
log.error( "Bad selector for artifact: {}", e.getMessage( ), e );
// continue
}
}
purge( artifactsToDelete );
return;
}
// ArtifactReference artifact = repository.toArtifactReference( path );
Calendar olderThanThisDate = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) );
olderThanThisDate.add( Calendar.DATE, -retentionPeriod );
ArchivaItemSelector selector = ArchivaItemSelector.builder( )
.withNamespace( artifactItem.getVersion( ).getProject( ).getNamespace( ).getId( ) )
.withProjectId( artifactItem.getVersion( ).getProject( ).getId( ) )
.withVersion( artifactItem.getVersion( ).getId( ) )
.withClassifier( "*" )
.includeRelatedArtifacts( )
.build( );
List<String> artifactVersions;
try ( Stream<? extends Artifact> stream = repository.getLayout( BaseRepositoryContentLayout.class ).newArtifactStream( selector ) )
{
artifactVersions = stream.map( a -> a.getArtifactVersion( ) )
.filter( StringUtils::isNotEmpty )
.distinct( )
.collect( Collectors.toList( ) );
}
Collections.sort( artifactVersions, VersionComparator.getInstance( ) );
if ( retentionCount > artifactVersions.size( ) )
{
// Done. nothing to do here. skip it.
return;
}
int countToPurge = artifactVersions.size( ) - retentionCount;
ArchivaItemSelector.Builder artifactSelectorBuilder = ArchivaItemSelector.builder( )
.withNamespace( artifactItem.getVersion( ).getProject( ).getNamespace( ).getId( ) )
.withProjectId( artifactItem.getVersion( ).getProject( ).getId( ) )
.withVersion( artifactItem.getVersion( ).getId( ) )
.withArtifactId( artifactItem.getId( ) )
.withClassifier( "*" )
.includeRelatedArtifacts( );
Set<Artifact> artifactsToDelete = new HashSet<>( );
for ( String version : artifactVersions )
{
if ( countToPurge-- <= 0 )
{
break;
}
ArchivaItemSelector artifactSelector = artifactSelectorBuilder.withArtifactVersion( version ).build( );
try
{
// Is this a generic snapshot "1.0-SNAPSHOT" ?
if ( VersionUtil.isGenericSnapshot( version ) )
{
List<? extends Artifact> artifactList = repository.getLayout( BaseRepositoryContentLayout.class ).getArtifacts( artifactSelector );
if ( artifactList.size( ) > 0 && artifactList.get( 0 ).getAsset( ).getModificationTime( ).toEpochMilli( ) < olderThanThisDate.getTimeInMillis( ) )
{
artifactsToDelete.addAll( artifactList );
}
}
// Is this a timestamp snapshot "1.0-20070822.123456-42" ?
else if ( VersionUtil.isUniqueSnapshot( version ) )
{
Calendar timestampCal = uniqueSnapshotToCalendar( version );
if ( timestampCal.getTimeInMillis( ) < olderThanThisDate.getTimeInMillis( ) )
{
artifactsToDelete.addAll( repository.getLayout( BaseRepositoryContentLayout.class ).getArtifacts( artifactSelector ) );
}
}
}
catch ( IllegalArgumentException e )
{
log.error( "Bad selector for artifact: {}", e.getMessage( ), e );
// continue
}
}
purge( artifactsToDelete );
}
catch ( LayoutException e )
{

View File

@ -21,12 +21,12 @@ package org.apache.archiva.consumers.core.repository;
import org.apache.archiva.common.utils.VersionComparator;
import org.apache.archiva.common.utils.VersionUtil;
import org.apache.archiva.metadata.audit.RepositoryListener;
import org.apache.archiva.metadata.repository.RepositorySession;
import org.apache.archiva.model.ArtifactReference;
import org.apache.archiva.repository.ManagedRepositoryContent;
import org.apache.archiva.repository.LayoutException;
import org.apache.archiva.repository.BaseRepositoryContentLayout;
import org.apache.archiva.metadata.audit.RepositoryListener;
import org.apache.archiva.repository.LayoutException;
import org.apache.archiva.repository.ManagedRepositoryContent;
import org.apache.archiva.repository.content.Artifact;
import org.apache.archiva.repository.content.ContentItem;
import org.apache.archiva.repository.content.base.ArchivaItemSelector;
@ -61,67 +61,65 @@ public class RetentionCountRepositoryPurge
try
{
ContentItem item = repository.toItem( path );
if (item instanceof Artifact )
BaseRepositoryContentLayout layout = repository.getLayout( BaseRepositoryContentLayout.class );
Artifact artifact = layout.adaptItem( Artifact.class, item );
if ( !artifact.exists( ) )
{
Artifact artifact = (Artifact) item;
if (!artifact.exists()) {
return;
}
if ( VersionUtil.isSnapshot( artifact.getVersion( ).getId( ) ) )
{
ArchivaItemSelector selector = ArchivaItemSelector.builder( )
.withNamespace( artifact.getVersion( ).getProject( ).getNamespace( ).getId( ) )
.withProjectId( artifact.getVersion( ).getProject( ).getId( ) )
.withArtifactId( artifact.getId( ) )
.withVersion( artifact.getVersion( ).getId( ) )
.withClassifier( "*" )
.includeRelatedArtifacts( )
.build( );
List<String> versions;
try ( Stream<? extends Artifact> stream = repository.getLayout( BaseRepositoryContentLayout.class ).newArtifactStream( selector ) )
{
versions = stream.map( a -> a.getArtifactVersion( ) )
.filter( StringUtils::isNotEmpty )
.distinct( )
.collect( Collectors.toList( ) );
}
Collections.sort( versions, VersionComparator.getInstance( ) );
if ( retentionCount > versions.size( ) )
{
log.trace( "No deletion, because retention count is higher than actual number of artifacts." );
// Done. nothing to do here. skip it.
return;
}
if ( VersionUtil.isSnapshot( artifact.getVersion( ).getId() ) )
ArchivaItemSelector.Builder selectorBuilder = ArchivaItemSelector.builder( )
.withNamespace( artifact.getVersion( ).getProject( ).getNamespace( ).getId( ) )
.withProjectId( artifact.getVersion( ).getProject( ).getId( ) )
.withArtifactId( artifact.getId( ) )
.withClassifier( "*" )
.includeRelatedArtifacts( )
.withVersion( artifact.getVersion( ).getId( ) );
int countToPurge = versions.size( ) - retentionCount;
Set<Artifact> artifactsToDelete = new HashSet<>( );
for ( String version : versions )
{
ArchivaItemSelector selector = ArchivaItemSelector.builder( )
.withNamespace( artifact.getVersion( ).getProject( ).getNamespace( ).getId( ) )
.withProjectId( artifact.getVersion( ).getProject( ).getId( ) )
.withArtifactId( artifact.getId( ) )
.withVersion( artifact.getVersion( ).getId( ) )
.withClassifier( "*" )
.includeRelatedArtifacts()
.build( );
List<String> versions;
try( Stream<? extends Artifact> stream = repository.getLayout( BaseRepositoryContentLayout.class ).newArtifactStream( selector) ){
versions = stream.map( a -> a.getArtifactVersion( ) )
.filter( StringUtils::isNotEmpty )
.distinct()
.collect( Collectors.toList( ) );
}
Collections.sort( versions, VersionComparator.getInstance( ) );
if ( retentionCount > versions.size( ) )
if ( countToPurge-- <= 0 )
{
log.trace( "No deletion, because retention count is higher than actual number of artifacts." );
// Done. nothing to do here. skip it.
return;
break;
}
ArchivaItemSelector.Builder selectorBuilder = ArchivaItemSelector.builder( )
.withNamespace( artifact.getVersion( ).getProject( ).getNamespace( ).getId( ) )
.withProjectId( artifact.getVersion( ).getProject( ).getId( ) )
.withArtifactId( artifact.getId( ) )
.withClassifier( "*" )
.includeRelatedArtifacts()
.withVersion( artifact.getVersion( ).getId( ) );
int countToPurge = versions.size( ) - retentionCount;
Set<Artifact> artifactsToDelete = new HashSet<>( );
for ( String version : versions )
List<? extends Artifact> delArtifacts = repository.getLayout( BaseRepositoryContentLayout.class ).getArtifacts( selectorBuilder.withArtifactVersion( version ).build( ) );
if ( delArtifacts != null && delArtifacts.size( ) > 0 )
{
if ( countToPurge-- <= 0 )
{
break;
}
List<? extends Artifact> delArtifacts = repository.getLayout( BaseRepositoryContentLayout.class ).getArtifacts( selectorBuilder.withArtifactVersion( version ).build( ) );
if (delArtifacts!=null && delArtifacts.size()>0)
{
artifactsToDelete.addAll( delArtifacts );
}
artifactsToDelete.addAll( delArtifacts );
}
purge( artifactsToDelete );
}
} else {
throw new RepositoryPurgeException( "Bad artifact path " + path );
purge( artifactsToDelete );
}
}
catch ( LayoutException le )

View File

@ -25,6 +25,7 @@ import org.apache.archiva.policies.ProxyDownloadException;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.RepositoryType;
import org.apache.archiva.repository.content.Artifact;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.archiva.repository.storage.StorageAsset;
import java.util.List;
@ -89,6 +90,21 @@ public interface RepositoryProxyHandler
StorageAsset fetchFromProxies( ManagedRepository repository, Artifact artifact )
throws ProxyDownloadException;
/**
* Performs the artifact fetch operation against the target repositories
* of the provided source repository.
* <p>
* If the artifact is found, it is downloaded and placed into the source repository
* filesystem.
*
* @param repository the source repository to use. (must be a managed repository)
* @param artifactSelector the artifact to fetch.
* @return the file that was obtained, or null if no content was obtained
* @throws ProxyDownloadException if there was a problem fetching the content from the target repositories.
*/
StorageAsset fetchFromProxies( ManagedRepository repository, ItemSelector artifactSelector )
throws ProxyDownloadException;
/**
* Performs the metadata fetch operation against the target repositories
* of the provided source repository.

View File

@ -50,6 +50,7 @@ import org.apache.archiva.repository.RemoteRepository;
import org.apache.archiva.repository.RemoteRepositoryContent;
import org.apache.archiva.repository.RepositoryType;
import org.apache.archiva.repository.content.Artifact;
import org.apache.archiva.repository.content.ContentItem;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.archiva.repository.content.base.ArchivaItemSelector;
import org.apache.archiva.repository.metadata.base.MetadataTools;
@ -206,6 +207,73 @@ public abstract class DefaultRepositoryProxyHandler implements RepositoryProxyHa
return null;
}
@Override
public StorageAsset fetchFromProxies( ManagedRepository repository, ItemSelector artifactSelector )
throws ProxyDownloadException
{
Map<String, Exception> previousExceptions = new LinkedHashMap<>();
ContentItem item = repository.getContent( ).getItem( artifactSelector );
StorageAsset localFile = item.getAsset( );
Properties requestProperties = new Properties();
requestProperties.setProperty( "filetype", "artifact" );
requestProperties.setProperty( "version", artifactSelector.getVersion() );
requestProperties.setProperty( "managedRepositoryId", repository.getId() );
List<ProxyConnector> connectors = getProxyConnectors( repository );
for ( ProxyConnector connector : connectors )
{
if ( !connector.isEnabled() )
{
continue;
}
RemoteRepository targetRepository = connector.getTargetRepository();
requestProperties.setProperty( "remoteRepositoryId", targetRepository.getId() );
StorageAsset targetFile = targetRepository.getAsset( localFile.getPath( ) );
// Removing the leading '/' from the path
String targetPath = targetFile.getPath( ).substring( 1 );
try
{
StorageAsset downloadedFile =
transferFile( connector, targetRepository, targetPath, repository, localFile, requestProperties,
true );
if ( fileExists(downloadedFile) )
{
log.debug( "Successfully transferred: {}", downloadedFile.getPath() );
return downloadedFile;
}
}
catch ( NotFoundException e )
{
log.debug( "Artifact {} not found on repository \"{}\".", item,
targetRepository.getId() );
}
catch ( NotModifiedException e )
{
log.debug( "Artifact {} not updated on repository \"{}\".", item,
targetRepository.getId() );
}
catch ( ProxyException e )
{
validatePolicies( this.downloadErrorPolicies, connector.getPolicies(), requestProperties, item,
targetRepository.getContent(), localFile, e, previousExceptions );
}
}
if ( !previousExceptions.isEmpty() )
{
throw new ProxyDownloadException( "Failures occurred downloading from some remote repositories",
previousExceptions );
}
log.debug( "Exhausted all target repositories, artifact {} not found.", item );
return null;
}
@Override
public StorageAsset fetchFromProxies( ManagedRepository repository, ArtifactReference artifact )
throws ProxyDownloadException
@ -736,7 +804,7 @@ public abstract class DefaultRepositoryProxyHandler implements RepositoryProxyHa
}
private void validatePolicies( Map<String, DownloadErrorPolicy> policies, Map<Policy, PolicyOption> settings,
Properties request, Artifact artifact, RemoteRepositoryContent content,
Properties request, ContentItem artifact, RemoteRepositoryContent content,
StorageAsset localFile, Exception exception, Map<String, Exception> previousExceptions )
throws ProxyDownloadException
{
@ -784,7 +852,7 @@ public abstract class DefaultRepositoryProxyHandler implements RepositoryProxyHa
log.warn(
"Transfer error from repository {} for artifact {} , continuing to next repository. Error message: {}",
content.getRepository().getId(), artifact.getId(), exception.getMessage() );
content.getRepository().getId(), artifact, exception.getMessage() );
log.debug( "Full stack trace", exception );
}

View File

@ -20,6 +20,7 @@ package org.apache.archiva.repository;
*/
import org.apache.archiva.model.ArtifactReference;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.archiva.repository.features.RepositoryFeature;
/**
@ -42,6 +43,15 @@ public interface RepositoryRequestInfo
*/
ArtifactReference toArtifactReference( String requestPath ) throws LayoutException;
/**
* Returns the item selector that matches the given path.
* @param requestPath the request path which may be different from the filesystem structure
* @return the item selector
* @throws LayoutException if the path is not valid for the given repository layout
*/
ItemSelector toItemSelector( String requestPath ) throws LayoutException;
/**
* <p>
* Tests the path to see if it conforms to the expectations of a metadata request.

View File

@ -20,6 +20,7 @@ package org.apache.archiva.repository.maven.content;
import org.apache.archiva.common.filelock.FileLockManager;
import org.apache.archiva.common.utils.FileUtils;
import org.apache.archiva.common.utils.VersionUtil;
import org.apache.archiva.configuration.FileTypes;
import org.apache.archiva.metadata.maven.MavenMetadataReader;
import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
@ -186,30 +187,42 @@ public class ManagedDefaultRepositoryContent
@Override
public <T extends ContentItem> T adaptItem( Class<T> clazz, ContentItem item ) throws LayoutException
{
if (clazz.isAssignableFrom( Version.class ))
try
{
if ( !item.hasCharacteristic( Version.class ) )
if ( clazz.isAssignableFrom( Version.class ) )
{
item.setCharacteristic( Version.class, createVersionFromPath( item.getAsset() ) );
if ( !item.hasCharacteristic( Version.class ) )
{
item.setCharacteristic( Version.class, createVersionFromPath( item.getAsset( ) ) );
}
return (T) item.adapt( Version.class );
}
return (T) item.adapt( Version.class );
} else if ( clazz.isAssignableFrom( Project.class )) {
if ( !item.hasCharacteristic( Project.class ) )
else if ( clazz.isAssignableFrom( Project.class ) )
{
item.setCharacteristic( Project.class, createProjectFromPath( item.getAsset() ) );
if ( !item.hasCharacteristic( Project.class ) )
{
item.setCharacteristic( Project.class, createProjectFromPath( item.getAsset( ) ) );
}
return (T) item.adapt( Project.class );
}
return (T) item.adapt( Project.class );
} else if ( clazz.isAssignableFrom( Namespace.class )) {
if ( !item.hasCharacteristic( Namespace.class ) )
else if ( clazz.isAssignableFrom( Namespace.class ) )
{
item.setCharacteristic( Namespace.class, createNamespaceFromPath( item.getAsset() ) );
if ( !item.hasCharacteristic( Namespace.class ) )
{
item.setCharacteristic( Namespace.class, createNamespaceFromPath( item.getAsset( ) ) );
}
return (T) item.adapt( Namespace.class );
}
return (T) item.adapt( Namespace.class );
} else if ( clazz.isAssignableFrom( Artifact.class )) {
if (!item.hasCharacteristic( Artifact.class )) {
item.setCharacteristic( Artifact.class, createArtifactFromPath( item.getAsset( ) ) );
else if ( clazz.isAssignableFrom( Artifact.class ) )
{
if ( !item.hasCharacteristic( Artifact.class ) )
{
item.setCharacteristic( Artifact.class, createArtifactFromPath( item.getAsset( ) ) );
}
return (T) item.adapt( Artifact.class );
}
return (T) item.adapt( Artifact.class );
} catch (LayoutRuntimeException e) {
throw new LayoutException( e.getMessage( ), e );
}
throw new LayoutException( "Could not convert item to class " + clazz);
}
@ -593,6 +606,7 @@ public class ManagedDefaultRepositoryContent
}
}
private DataItem getDataItemFromPath( final StorageAsset artifactPath )
{
final String contentType = getContentType( artifactPath );
@ -644,13 +658,13 @@ public class ManagedDefaultRepositoryContent
private ArtifactType artifactType = BaseArtifactTypes.MAIN;
}
private ArtifactInfo getArtifactInfoFromPath( String genericVersion, StorageAsset path )
private ArtifactInfo getArtifactInfoFromPath( final String genericVersion, final StorageAsset path )
{
final ArtifactInfo info = new ArtifactInfo( );
info.asset = path;
info.id = path.getParent( ).getParent( ).getName( );
final String fileName = path.getName( );
if ( genericVersion.endsWith( "-" + SNAPSHOT ) )
if ( VersionUtil.isGenericSnapshot( genericVersion ) )
{
String baseVersion = StringUtils.substringBeforeLast( genericVersion, "-" + SNAPSHOT );
String prefix = info.id + "-" + baseVersion + "-";
@ -722,7 +736,7 @@ public class ManagedDefaultRepositoryContent
else
{
String prefix = info.id + "-" + genericVersion;
if ( fileName.startsWith( prefix ) )
if ( fileName.startsWith( prefix + "-") )
{
info.version = genericVersion;
String classPostfix = StringUtils.removeStart( fileName, prefix );
@ -737,6 +751,24 @@ public class ManagedDefaultRepositoryContent
info.classifier = "";
info.remainder = classPostfix;
}
} else if (fileName.startsWith(prefix + ".")) {
info.version = genericVersion;
info.remainder = StringUtils.removeStart( fileName, prefix );
info.classifier = "";
} else if (fileName.startsWith(info.id+"-")) {
String postFix = StringUtils.removeStart( fileName, info.id + "-" );
String versionPart = StringUtils.substringBefore( postFix, "." );
if (VersionUtil.isVersion(versionPart)) {
info.version = versionPart;
info.remainder = StringUtils.removeStart( postFix, versionPart );
info.classifier = "";
} else {
info.version = "";
info.classifier = "";
int dotPos = fileName.indexOf( "." );
info.remainder = fileName.substring( dotPos );
}
}
else
{
@ -747,10 +779,10 @@ public class ManagedDefaultRepositoryContent
else
{
info.id = fileName;
info.version = "";
}
log.debug( "Artifact does not match the version pattern {}", path );
info.artifactType = BaseArtifactTypes.UNKNOWN;
info.version = "";
info.classifier = "";
info.remainder = StringUtils.substringAfterLast( fileName, "." );
}
@ -1454,16 +1486,40 @@ public class ManagedDefaultRepositoryContent
@Override
public ContentItem toItem( String path ) throws LayoutException
{
StorageAsset asset = getRepository( ).getAsset( path );
if ( asset.isLeaf( ) )
{
ItemSelector selector = getPathParser( ).toItemSelector( path );
return getItem( selector );
}
else
{
return getItemFromPath( asset );
ContentItem item = getItemFromPath( asset );
if (item instanceof DataItem) {
Artifact artifact = adaptItem( Artifact.class, item );
if (asset.getParent()==null) {
throw new LayoutException( "Path too short for maven artifact "+path );
}
String version = asset.getParent( ).getName( );
if (asset.getParent().getParent()==null) {
throw new LayoutException( "Path too short for maven artifact " + path );
}
String project = item.getAsset( ).getParent( ).getParent( ).getName( );
DataItem dataItem = (DataItem) item;
if (StringUtils.isEmpty( dataItem.getExtension())) {
throw new LayoutException( "Missing type on maven artifact" );
}
if (!project.equals(artifact.getId())) {
throw new LayoutException( "The maven artifact id "+artifact.getId() +" does not match the project id: " + project);
}
boolean versionIsGenericSnapshot = VersionUtil.isGenericSnapshot( version );
boolean artifactVersionIsSnapshot = VersionUtil.isSnapshot( artifact.getArtifactVersion() );
if ( versionIsGenericSnapshot && !artifactVersionIsSnapshot ) {
throw new LayoutException( "The maven artifact has no snapshot version in snapshot directory " + dataItem );
}
if ( !versionIsGenericSnapshot && artifactVersionIsSnapshot) {
throw new LayoutException( "The maven artifact version " + artifact.getArtifactVersion() + " is a snapshot version but inside a non snapshot directory " + version );
}
if ( !versionIsGenericSnapshot && !version.equals( artifact.getArtifactVersion() ) )
{
throw new LayoutException( "The maven artifact version " + artifact.getArtifactVersion() + " does not match the version directory " + version );
}
}
return item;
}
@Override

View File

@ -20,6 +20,7 @@ package org.apache.archiva.repository.maven.content;
import org.apache.archiva.model.ArtifactReference;
import org.apache.archiva.repository.*;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.archiva.repository.content.PathParser;
import org.apache.archiva.repository.features.RepositoryFeature;
import org.apache.archiva.repository.metadata.base.MetadataTools;
@ -82,6 +83,12 @@ public class MavenRepositoryRequestInfo implements RepositoryRequestInfo
}
}
@Override
public ItemSelector toItemSelector( String requestPath ) throws LayoutException
{
return repository.getContent( ).toItemSelector( requestPath );
}
/**
* <p>
* Tests the path to see if it conforms to the expectations of a metadata request.
@ -275,12 +282,18 @@ public class MavenRepositoryRequestInfo implements RepositoryRequestInfo
* Default layout is the only layout that can contain maven-metadata.xml files, and
* if the managedRepository is layout legacy, this request would never occur.
*/
return requestedPath;
if (requestedPath.startsWith( "/" )) {
return requestedPath;
} else
{
return "/"+requestedPath;
}
}
// Treat as an artifact reference.
ArtifactReference ref = toArtifactReference( referencedResource );
String adjustedPath = repository.getContent().toPath( ref );
String adjustedPath = repository.getContent( ).toPath( repository.getContent( ).toItem( requestedPath ) );
return adjustedPath + supportfile;
}

View File

@ -644,6 +644,98 @@ public class Maven2RepositoryStorage
}
}
@Override
public ItemSelector applyServerSideRelocation(ManagedRepository managedRepository, ItemSelector artifactSelector)
throws ProxyDownloadException {
if ("pom".equals(artifactSelector.getType())) {
return artifactSelector;
}
// Build the artifact POM reference
BaseRepositoryContentLayout layout;
try
{
layout = managedRepository.getContent( ).getLayout( BaseRepositoryContentLayout.class );
}
catch ( LayoutException e )
{
throw new ProxyDownloadException( "Could not set layout " + e.getMessage( ), new HashMap<>( ) );
}
RepositoryType repositoryType = managedRepository.getType();
if (!proxyRegistry.hasHandler(repositoryType)) {
throw new ProxyDownloadException("No proxy handler found for repository type " + repositoryType, new HashMap<>());
}
ItemSelector selector = ArchivaItemSelector.builder( )
.withNamespace( artifactSelector.getNamespace( ) )
.withProjectId( artifactSelector.getArtifactId( ) )
.withArtifactId( artifactSelector.getArtifactId( ) )
.withVersion( artifactSelector.getVersion( ) )
.withArtifactVersion( artifactSelector.getVersion( ) )
.withType( "pom" ).build( );
Artifact pom = layout.getArtifact( selector );
RepositoryProxyHandler proxyHandler = proxyRegistry.getHandler(repositoryType).get(0);
// Get the artifact POM from proxied repositories if needed
proxyHandler.fetchFromProxies(managedRepository, pom);
// Open and read the POM from the managed repo
if (!pom.exists()) {
return artifactSelector;
}
try {
// MavenXpp3Reader leaves the file open, so we need to close it ourselves.
Model model;
try (Reader reader = Channels.newReader(pom.getAsset().getReadChannel(), Charset.defaultCharset().name())) {
model = MAVEN_XPP_3_READER.read(reader);
}
DistributionManagement dist = model.getDistributionManagement();
if (dist != null) {
Relocation relocation = dist.getRelocation();
if (relocation != null) {
ArchivaItemSelector.Builder relocatedBuilder = ArchivaItemSelector.builder( );
// artifact is relocated : update the repositoryPath
if (relocation.getGroupId() != null) {
relocatedBuilder.withNamespace( relocation.getGroupId( ) );
} else {
relocatedBuilder.withNamespace( artifactSelector.getNamespace( ) );
}
if (relocation.getArtifactId() != null) {
relocatedBuilder.withArtifactId( relocation.getArtifactId( ) );
} else {
relocatedBuilder.withArtifactId( artifactSelector.getArtifactId( ) );
}
if (relocation.getVersion() != null)
{
relocatedBuilder.withVersion( relocation.getVersion( ) );
} else {
relocatedBuilder.withVersion( artifactSelector.getVersion( ) );
}
return relocatedBuilder.withArtifactVersion( artifactSelector.getArtifactVersion( ) )
.withClassifier( artifactSelector.getClassifier( ) )
.withType( artifactSelector.getType( ) )
.withProjectId( artifactSelector.getProjectId( ) )
.withExtension( artifactSelector.getExtension( ) )
.build( );
}
}
} catch (IOException e) {
// Unable to read POM : ignore.
} catch (XmlPullParserException e) {
// Invalid POM : ignore
}
return artifactSelector;
}
@Override
public String getFilePath(String requestPath, org.apache.archiva.repository.ManagedRepository managedRepository) {

View File

@ -1014,7 +1014,7 @@ public class ManagedDefaultRepositoryContentTest
path = "/org/apache/maven/shared/maven-downloader/1.1/maven-downloader-1.1.jar";
item = repoContent.toItem( path );
assertNotNull( item );
assertTrue( item instanceof Artifact );
assertTrue( item instanceof DataItem );
}

View File

@ -72,6 +72,9 @@ public class MavenRepositoryRequestInfoTest
@Inject
FileLockManager fileLockManager;
@Inject
MavenContentHelper mavenContentHelper;
private MavenRepositoryRequestInfo repoRequest;
@ -109,6 +112,8 @@ public class MavenRepositoryRequestInfoTest
ManagedDefaultRepositoryContent repoContent = new ManagedDefaultRepositoryContent(repository, artifactMappingProviders, fileTypes, fileLockManager);
//repoContent = (ManagedRepositoryContent) lookup( ManagedRepositoryContent.class, "default" );
repository.setContent(repoContent);
repoContent.setMavenContentHelper( mavenContentHelper );
repoRequest = new MavenRepositoryRequestInfo(repository);
}
@ -430,7 +435,7 @@ public class MavenRepositoryRequestInfoTest
ManagedRepositoryContent repository = createManagedRepo( "default" );
// Test (artifact) default to default - dual extension
assertEquals( "org/project/example-presentation/3.2/example-presentation-3.2.xml.zip",
assertEquals( "/org/project/example-presentation/3.2/example-presentation-3.2.xml.zip",
repoRequest.toNativePath( "org/project/example-presentation/3.2/example-presentation-3.2.xml.zip") );
}
@ -442,7 +447,7 @@ public class MavenRepositoryRequestInfoTest
ManagedRepositoryContent repository = createManagedRepo( "default" );
// Test (metadata) default to default
assertEquals( "org/apache/derby/derby/10.2.2.0/maven-metadata.xml.sha1",
assertEquals( "/org/apache/derby/derby/10.2.2.0/maven-metadata.xml.sha1",
repoRequest.toNativePath( "org/apache/derby/derby/10.2.2.0/maven-metadata.xml.sha1") );
}

View File

@ -31,6 +31,7 @@ import org.apache.archiva.components.taskqueue.TaskQueueException;
import org.apache.archiva.repository.ManagedRepositoryContent;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.metadata.audit.RepositoryListener;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.archiva.scheduler.repository.model.RepositoryArchivaTaskScheduler;
import org.apache.archiva.scheduler.repository.model.RepositoryTask;
import org.apache.archiva.xml.XMLException;
@ -108,6 +109,12 @@ public class MockBeanServices
}
@Override
public ItemSelector applyServerSideRelocation( ManagedRepository managedRepository, ItemSelector selector ) throws ProxyDownloadException
{
return null;
}
@Override
public void deleteArtifact( MetadataRepository metadataRepository, String repositoryId, String namespace,

View File

@ -68,6 +68,7 @@ import org.apache.archiva.repository.RepositoryRegistry;
import org.apache.archiva.repository.RepositoryRequestInfo;
import org.apache.archiva.repository.content.Artifact;
import org.apache.archiva.repository.content.ContentItem;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.archiva.repository.storage.fs.FilesystemStorage;
import org.apache.archiva.repository.storage.StorageAsset;
import org.apache.archiva.metadata.audit.AuditListener;
@ -791,22 +792,23 @@ public class ArchivaDavResourceFactory
try
{
// Get the artifact reference in a layout neutral way.
ArtifactReference artifact = repositoryRequestInfo.toArtifactReference( path );
// ArtifactReference artifact = repositoryRequestInfo.toArtifactReference( path );
ItemSelector selector = repositoryRequestInfo.toItemSelector( path );
if ( artifact != null )
if ( selector != null )
{
String repositoryLayout = managedRepository.getLayout();
RepositoryStorage repositoryStorage =
this.applicationContext.getBean( "repositoryStorage#" + repositoryLayout, RepositoryStorage.class );
repositoryStorage.applyServerSideRelocation( managedRepository, artifact );
selector = repositoryStorage.applyServerSideRelocation( managedRepository, selector );
StorageAsset proxiedFile = proxyHandler.fetchFromProxies( managedRepository, artifact );
StorageAsset proxiedFile = proxyHandler.fetchFromProxies( managedRepository, selector );
resource.setPath( managedRepository.getContent().toPath( artifact ) );
resource.setPath( managedRepository.getContent().toPath( selector ) );
log.debug( "Proxied artifact '{}:{}:{}'", artifact.getGroupId(), artifact.getArtifactId(),
artifact.getVersion() );
log.debug( "Proxied artifact '{}:{}:{}:{}'", selector.getNamespace(), selector.getArtifactId(),
selector.getVersion(), selector.getArtifactVersion() );
return ( proxiedFile != null );
}

View File

@ -27,6 +27,7 @@ import org.apache.archiva.model.ArtifactReference;
import org.apache.archiva.policies.ProxyDownloadException;
import org.apache.archiva.repository.ManagedRepositoryContent;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.archiva.xml.XMLException;
import java.io.IOException;
@ -74,6 +75,21 @@ public interface RepositoryStorage
void applyServerSideRelocation( ManagedRepository managedRepository, ArtifactReference artifact )
throws ProxyDownloadException;
/**
* A relocation capable client will request the POM prior to the artifact, and will then read meta-data and do
* client side relocation. A simplier client (like maven 1) will only request the artifact and not use the
* metadatas.
* <p>
* For such clients, archiva does server-side relocation by reading itself the &lt;relocation&gt; element in
* metadatas and serving the expected artifact.
* @param managedRepository the used managed repository
* @param artifact the artifact reference
* @throws org.apache.archiva.policies.ProxyDownloadException
*/
ItemSelector applyServerSideRelocation( ManagedRepository managedRepository, ItemSelector selector )
throws ProxyDownloadException;
/**
* add an other method to evaluate real path as when receiving -SNAPSHOT (for maven storage)
* request redirect to the last build

View File

@ -37,6 +37,7 @@ import org.apache.archiva.policies.ProxyDownloadException;
import org.apache.archiva.repository.ManagedRepositoryContent;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.metadata.audit.RepositoryListener;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.archiva.xml.XMLException;
import java.io.IOException;
@ -112,6 +113,12 @@ public class MockRepositoryStorage
}
@Override
public ItemSelector applyServerSideRelocation( ManagedRepository managedRepository, ItemSelector selector ) throws ProxyDownloadException
{
return null;
}
@Override
public String getFilePath( String requestPath, org.apache.archiva.repository.ManagedRepository managedRepository )
{