@@ -194,4 +194,6 @@ public class VersionUtil | |||
} | |||
return version; | |||
} | |||
} |
@@ -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; | |||
return; | |||
} | |||
if ( !artifactItem.exists( ) ) | |||
{ | |||
return; | |||
} | |||
// ArtifactReference artifact = repository.toArtifactReference( path ); | |||
// 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( ) ); | |||
} | |||
Calendar olderThanThisDate = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ); | |||
olderThanThisDate.add( Calendar.DATE, -retentionPeriod ); | |||
Collections.sort( artifactVersions, VersionComparator.getInstance( ) ); | |||
ArchivaItemSelector selector = ArchivaItemSelector.builder( ) | |||
.withNamespace( artifactItem.getVersion( ).getProject( ).getNamespace( ).getId( ) ) | |||
.withProjectId( artifactItem.getVersion( ).getProject( ).getId( ) ) | |||
.withVersion( artifactItem.getVersion( ).getId( ) ) | |||
.withClassifier( "*" ) | |||
.includeRelatedArtifacts( ) | |||
.build( ); | |||
if ( retentionCount > artifactVersions.size( ) ) | |||
{ | |||
// Done. nothing to do here. skip it. | |||
return; | |||
} | |||
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( ) ); | |||
int countToPurge = artifactVersions.size( ) - retentionCount; | |||
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 ) | |||
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 ) | |||
{ | |||
if ( countToPurge-- <= 0 ) | |||
{ | |||
break; | |||
} | |||
break; | |||
} | |||
ArchivaItemSelector artifactSelector = artifactSelectorBuilder.withArtifactVersion( version ).build( ); | |||
try | |||
{ | |||
ArchivaItemSelector artifactSelector = artifactSelectorBuilder.withArtifactVersion( version ).build( ); | |||
try | |||
{ | |||
// Is this a generic snapshot "1.0-SNAPSHOT" ? | |||
if ( VersionUtil.isGenericSnapshot( version ) ) | |||
// 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( ) ) | |||
{ | |||
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 ); | |||
} | |||
artifactsToDelete.addAll( artifactList ); | |||
} | |||
// Is this a timestamp snapshot "1.0-20070822.123456-42" ? | |||
else if ( VersionUtil.isUniqueSnapshot( version ) ) | |||
{ | |||
Calendar timestampCal = uniqueSnapshotToCalendar( version ); | |||
} | |||
// 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 ) ); | |||
} | |||
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 ( IllegalArgumentException e ) | |||
{ | |||
log.error( "Bad selector for artifact: {}", e.getMessage( ), e ); | |||
// continue | |||
} | |||
} | |||
purge( artifactsToDelete ); | |||
} | |||
catch ( LayoutException e ) | |||
{ |
@@ -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; | |||
} | |||
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( ); | |||
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( ) ); | |||
} | |||
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( ) ); | |||
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 ( retentionCount > versions.size( ) ) | |||
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 ) | |||
{ | |||
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 ) |
@@ -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. |
@@ -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 ); | |||
} | |||
@@ -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. |
@@ -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 |
@@ -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; | |||
} | |||
@@ -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) { |
@@ -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 ); | |||
} | |||
@@ -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") ); | |||
} | |||
@@ -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, |
@@ -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 ); | |||
} |
@@ -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 <relocation> 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 |
@@ -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 ) | |||
{ |