public class ArchivaItemSelector implements ItemSelector
{
- private String projectId = null;
- private String version = null;
- private String artifactVersion = null;
- private String artifactId = null;
+ private String projectId = "";
+ private String version = "";
+ private String artifactVersion = "";
+ private String artifactId = "";
private String namespace = "";
- private String type = null;
- private String classifier = null;
- private String extension = null;
+ private String type = "";
+ private String classifier = "";
+ private String extension = "";
private Map<String, String> attributes;
- private boolean searchRelatedArtifacts = false;
- private boolean searchSubNamespaces = false;
+ private boolean includeRelatedArtifacts = false;
+ private boolean recurse = false;
private ArchivaItemSelector( )
public Builder withNamespace( String namespace )
{
- selector.namespace = namespace;
+ if (namespace!=null)
+ {
+ selector.namespace = namespace;
+ }
return this;
}
public Builder withProjectId( String projectId )
{
- selector.projectId = projectId;
+ if (projectId!=null)
+ {
+ selector.projectId = projectId;
+ }
return this;
}
public Builder withVersion( String version )
{
- selector.version = version;
+ if (version!=null)
+ {
+ selector.version = version;
+ }
return this;
}
public Builder withArtifactVersion( String artifactVersion )
{
- selector.artifactVersion = artifactVersion;
+ if (artifactVersion!=null)
+ {
+ selector.artifactVersion = artifactVersion;
+ }
return this;
}
public Builder withArtifactId( String artifactId )
{
- selector.artifactId = artifactId;
+ if (artifactId!=null)
+ {
+ selector.artifactId = artifactId;
+ }
return this;
}
public Builder withType( String type )
{
- selector.type = type;
+ if (type!=null)
+ {
+ selector.type = type;
+ }
return this;
}
public Builder withClassifier( String classifier )
{
- selector.classifier = classifier;
+ if (classifier != null )
+ {
+ selector.classifier = classifier;
+ }
return this;
}
public Builder withExtension( String extension )
{
- selector.extension = extension;
+ if (extension!=null)
+ {
+ selector.extension = extension;
+ }
return this;
}
- public Builder enableSearchRelatedArtifacts() {
- selector.searchRelatedArtifacts = true;
+ public Builder includeRelatedArtifacts() {
+ selector.includeRelatedArtifacts = true;
return this;
}
- public Builder enableSearchSubNamespaces() {
- selector.searchSubNamespaces = true;
+ public Builder recurse() {
+ selector.recurse = true;
return this;
}
}
@Override
- public boolean searchSubNamespaces( )
+ public boolean recurse( )
{
- return searchSubNamespaces;
+ return recurse;
}
@Override
- public boolean findRelatedArtifacts( )
+ public boolean includeRelatedArtifacts( )
{
- return searchRelatedArtifacts;
+ return includeRelatedArtifacts;
}
@Override
{
return StringUtils.isNotEmpty( extension );
}
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if ( this == o ) return true;
+ if ( o == null || getClass( ) != o.getClass( ) ) return false;
+
+ ArchivaItemSelector that = (ArchivaItemSelector) o;
+
+ if ( includeRelatedArtifacts != that.includeRelatedArtifacts ) return false;
+ if ( recurse != that.recurse ) return false;
+ if ( !projectId.equals( that.projectId ) ) return false;
+ if ( !version.equals( that.version ) ) return false;
+ if ( !artifactVersion.equals( that.artifactVersion ) ) return false;
+ if ( !artifactId.equals( that.artifactId ) ) return false;
+ if ( !namespace.equals( that.namespace ) ) return false;
+ if ( !type.equals( that.type ) ) return false;
+ if ( !classifier.equals( that.classifier ) ) return false;
+ if ( !extension.equals( that.extension ) ) return false;
+ return attributes != null ? attributes.equals( that.attributes ) : that.attributes == null;
+ }
+
+ @Override
+ public int hashCode( )
+ {
+ int result = projectId.hashCode( );
+ result = 31 * result + version.hashCode( );
+ result = 31 * result + artifactVersion.hashCode( );
+ result = 31 * result + artifactId.hashCode( );
+ result = 31 * result + namespace.hashCode( );
+ result = 31 * result + type.hashCode( );
+ result = 31 * result + classifier.hashCode( );
+ result = 31 * result + extension.hashCode( );
+ result = 31 * result + ( attributes != null ? attributes.hashCode( ) : 0 );
+ result = 31 * result + ( includeRelatedArtifacts ? 1 : 0 );
+ result = 31 * result + ( recurse ? 1 : 0 );
+ return result;
+ }
}
import org.apache.archiva.configuration.FileTypes;
import org.apache.archiva.metadata.maven.MavenMetadataReader;
import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
-import org.apache.archiva.repository.maven.metadata.storage.ArtifactMappingProvider;
-import org.apache.archiva.repository.maven.metadata.storage.DefaultArtifactMappingProvider;
import org.apache.archiva.model.ArchivaArtifact;
import org.apache.archiva.model.ArtifactReference;
import org.apache.archiva.model.ProjectReference;
import org.apache.archiva.repository.content.Namespace;
import org.apache.archiva.repository.content.Project;
import org.apache.archiva.repository.content.Version;
+import org.apache.archiva.repository.content.base.ArchivaItemSelector;
import org.apache.archiva.repository.content.base.ArchivaNamespace;
import org.apache.archiva.repository.content.base.ArchivaProject;
import org.apache.archiva.repository.content.base.ArchivaVersion;
import org.apache.archiva.repository.content.base.builder.ArtifactOptBuilder;
+import org.apache.archiva.repository.maven.metadata.storage.ArtifactMappingProvider;
+import org.apache.archiva.repository.maven.metadata.storage.DefaultArtifactMappingProvider;
import org.apache.archiva.repository.storage.RepositoryStorage;
import org.apache.archiva.repository.storage.StorageAsset;
import org.apache.archiva.repository.storage.util.StorageUtil;
import javax.inject.Inject;
import javax.inject.Named;
+import javax.naming.Name;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
/**
* ManagedDefaultRepositoryContent
return getStorage( ).getAsset( path.toString( ) );
}
- /*
- * File filter to select certain artifacts using the selector data.
- */
- private Predicate<StorageAsset> getFileFilterFromSelector(final ItemSelector selector) {
- Predicate<StorageAsset> p = a -> a.isLeaf( );
- StringBuilder fileNamePattern = new StringBuilder("^" );
- if (selector.hasArtifactId()) {
- fileNamePattern.append( Pattern.quote(selector.getArtifactId( )) ).append("-");
- } else {
- fileNamePattern.append("[A-Za-z0-9_\\-.]+-");
- }
- if (selector.hasArtifactVersion()) {
- fileNamePattern.append( Pattern.quote(selector.getArtifactVersion( )) );
- } else {
- fileNamePattern.append( "[A-Za-z0-9_\\-.]+" );
- }
- String classifier = selector.hasClassifier( ) ? selector.getClassifier( ) :
- ( selector.hasType( ) ? MavenContentHelper.getClassifierFromType( selector.getType( ) ) : null );
- if (classifier != null)
- {
- if ( "*".equals( classifier ) )
- {
- fileNamePattern.append( "-[A-Za-z0-9]+\\." );
- }
- else
- {
- fileNamePattern.append("-").append( Pattern.quote( classifier ) ).append( "\\." );
- }
- } else {
- fileNamePattern.append( "\\." );
- }
- String extension = selector.hasExtension( ) ? selector.getExtension( ) :
- ( selector.hasType( ) ? MavenContentHelper.getArtifactExtension( selector ) : null );
- if (extension != null) {
- fileNamePattern.append( Pattern.quote( extension ) );
- } else {
- fileNamePattern.append( ".*" );
- }
- final Pattern pattern = Pattern.compile( fileNamePattern.toString() );
- return p.and( a -> pattern.matcher( a.getName( ) ).matches());
- }
-
/**
* Returns all the subdirectories of the given namespace directory as project.
}
- /*
- TBD
- */
+ /**
+ * See {@link #newArtifactStream(ItemSelector)}. This method collects the stream into a list.
+ *
+ * @param selector the selector for the artifacts
+ * @return the list of artifacts
+ * @throws ContentAccessException if the access to the underlying filesystem failed
+ */
@Override
public List<? extends Artifact> getArtifacts( ItemSelector selector ) throws ContentAccessException
{
- return null;
+ try(Stream<? extends Artifact> stream = newArtifactStream( selector )) {
+ return stream.collect( Collectors.toList());
+ }
}
+
/*
- TBD
+ * File filter to select certain artifacts using the selector data.
+ */
+ private Predicate<StorageAsset> getFileFilterFromSelector(final ItemSelector selector) {
+ Predicate<StorageAsset> p = a -> a.isLeaf( );
+ StringBuilder fileNamePattern = new StringBuilder("^" );
+ if (selector.hasArtifactId()) {
+ fileNamePattern.append( Pattern.quote(selector.getArtifactId( )) ).append("-");
+ } else {
+ fileNamePattern.append("[A-Za-z0-9_\\-.]+-");
+ }
+ if (selector.hasArtifactVersion()) {
+ fileNamePattern.append( Pattern.quote(selector.getArtifactVersion( )) );
+ } else {
+ fileNamePattern.append( "[A-Za-z0-9_\\-.]+" );
+ }
+ String classifier = selector.hasClassifier( ) ? selector.getClassifier( ) :
+ ( selector.hasType( ) ? MavenContentHelper.getClassifierFromType( selector.getType( ) ) : null );
+ if (classifier != null)
+ {
+ if ( "*".equals( classifier ) )
+ {
+ fileNamePattern.append( "-[A-Za-z0-9]+\\." );
+ }
+ else
+ {
+ fileNamePattern.append("-").append( Pattern.quote( classifier ) ).append( "\\." );
+ }
+ } else {
+ fileNamePattern.append( "\\." );
+ }
+ String extension = selector.hasExtension( ) ? selector.getExtension( ) :
+ ( selector.hasType( ) ? MavenContentHelper.getArtifactExtension( selector ) : null );
+ if (extension != null) {
+ if (selector.includeRelatedArtifacts())
+ {
+ fileNamePattern.append( Pattern.quote( extension ) ).append("(\\.[A-Za-z0-9]+)?");
+ } else {
+ fileNamePattern.append( Pattern.quote( extension ) );
+ }
+ } else {
+ fileNamePattern.append( "[A-Za-z0-9]+" );
+ }
+ final Pattern pattern = Pattern.compile( fileNamePattern.toString() );
+ return p.and( a -> pattern.matcher( a.getName( ) ).matches());
+ }
+
+
+ /**
+ * Returns the artifacts. The number of artifacts returned depend on the selector.
+ * If the selector sets the flag {@link ItemSelector#includeRelatedArtifacts()} to <code>true</code>,
+ * additional to the matching artifacts, related artifacts like hash values or signatures are included in the artifact
+ * stream.
+ * If the selector sets the flag {@link ItemSelector#recurse()} to <code>true</code>, artifacts of the given
+ * namespace and from all sub namespaces that start with the given namespace are returned.
+ * <ul>
+ * <li>If only a namespace is given, all artifacts with the given namespace or starting with the given
+ * namespace (see {@link ItemSelector#recurse()} are returned.</li>
+ * <li>If a namespace and a project id, or artifact id is given, the artifacts of all versions of the given
+ * namespace and project are returned.</li>
+ * <li>If a namespace and a project id or artifact id and a version is given, the artifacts of the given
+ * version are returned</li>
+ * </ul>
+ *
+ * There is no determinate order of the elements in the stream.
+ *
+ * Returned streams are auto closable and should be used in a try-with-resources statement.
+ *
+ * @param selector the item selector
+ * @throws ContentAccessException if the access to the underlying filesystem failed
*/
@Override
- public Stream<? extends Artifact> getArtifactStream( ItemSelector selector ) throws ContentAccessException
+ public Stream<? extends Artifact> newArtifactStream( ItemSelector selector ) throws ContentAccessException
{
- return null;
+ String projectId = selector.hasProjectId( ) ? selector.getProjectId( ) : ( selector.hasArtifactId( ) ? selector.getArtifactId( )
+ : null );
+ final Predicate<StorageAsset> filter = getFileFilterFromSelector( selector );
+ if (projectId!=null && selector.hasVersion()) {
+ return getAsset( selector.getNamespace( ), projectId, selector.getVersion( ) )
+ .list( ).stream( ).filter( filter )
+ .map( this::getArtifactFromPath );
+ } else if (projectId!=null) {
+ final StorageAsset projDir = getAsset( selector.getNamespace( ), projectId );
+ return projDir.list( ).stream( ).filter( StorageAsset::isContainer )
+ .map( StorageAsset::list )
+ .flatMap( List::stream )
+ .filter( filter )
+ .map( this::getArtifactFromPath );
+ } else
+ {
+ StorageAsset namespaceDir = getAsset( selector.getNamespace( ) );
+ if (selector.recurse())
+ {
+ return StorageUtil.newAssetStream( namespaceDir, true )
+ .filter( filter )
+ .map( this::getArtifactFromPath );
+
+ } else {
+ return namespaceDir.list( ).stream( )
+ .filter( StorageAsset::isContainer )
+ .map( StorageAsset::list )
+ .flatMap( List::stream )
+ .filter( StorageAsset::isContainer )
+ .map( StorageAsset::list )
+ .flatMap( List::stream )
+ .filter( filter )
+ .map(this::getArtifactFromPath);
+ }
+ }
}
- /*
- TBD
- */
+ /**
+ * Same as {@link #newArtifactStream(ContentItem)} but returns the collected stream as list.
+ *
+ * @param item the item the parent item
+ * @return the list of artifacts or a empty list of no artifacts where found
+ */
@Override
public List<? extends Artifact> getArtifacts( ContentItem item )
{
- return null;
+ try(Stream<? extends Artifact> stream = newArtifactStream( item )) {
+ return stream.collect( Collectors.toList());
+ }
}
+ /**
+ * Returns all artifacts
+ * @param item
+ * @return
+ * @throws ContentAccessException
+ */
+ public Stream<? extends Artifact> newArtifactStream( Namespace item ) throws ContentAccessException
+ {
+ return newArtifactStream( ArchivaItemSelector.builder( ).withNamespace( item.getNamespace( ) ).build( ) );
+ }
- /*
- TBD
+ public Stream<? extends Artifact> newArtifactStream( Project item ) throws ContentAccessException
+ {
+ return newArtifactStream( ArchivaItemSelector.builder( ).withNamespace( item.getNamespace( ).getNamespace() )
+ .withProjectId( item.getId() ).build( ) );
+ }
+
+ public Stream<? extends Artifact> newArtifactStream( Version item ) throws ContentAccessException
+ {
+ return newArtifactStream( ArchivaItemSelector.builder( ).withNamespace( item.getProject().getNamespace( ).getNamespace() )
+ .withProjectId( item.getProject().getId() )
+ .withVersion( item.getVersion() ).build( ) );
+ }
+
+ /**
+ * Returns all related artifacts that match the given artifact. That means all artifacts that have
+ * the same filename plus an additional extension, e.g. ${fileName}.sha2
+ * @param item the artifact
+ * @return the stream of artifacts
+ * @throws ContentAccessException
+ */
+ public Stream<? extends Artifact> newArtifactStream( Artifact item ) throws ContentAccessException
+ {
+ final Version v = item.getVersion( );
+ final String fileName = item.getFileName( );
+ final Predicate<StorageAsset> filter = ( StorageAsset a ) ->
+ a.getName( ).startsWith( fileName + "." );
+ return v.getAsset( ).list( ).stream( ).filter( filter )
+ .map( a -> getArtifactFromPath( a ) );
+ }
+ /**
+ * Returns the stream of artifacts that are children of the given item.
+ *
+ * @param item the item from where the artifacts should be returned
+ * @return
+ * @throws ContentAccessException
*/
@Override
- public Stream<? extends Artifact> getArtifactStream( ContentItem item )
+ public Stream<? extends Artifact> newArtifactStream( ContentItem item ) throws ContentAccessException
{
- return null;
+ if (item instanceof Namespace) {
+ return newArtifactStream( ( (Namespace) item ) );
+ } else if (item instanceof Project) {
+ return newArtifactStream( (Project) item );
+ } else if (item instanceof Version) {
+ return newArtifactStream( (Version) item );
+ } else if (item instanceof Artifact) {
+ return newArtifactStream( (Artifact) item );
+ } else
+ {
+ log.warn( "newArtifactStream for unsupported item requested: {}", item.getClass( ).getName( ) );
+ return Stream.empty( );
+ }
}
/**
public Set<String> getVersions( VersionedReference reference )
throws ContentNotFoundException, ContentAccessException, LayoutException
{
- try(Stream<ArtifactReference> stream = getArtifactStream( reference ))
+ try(Stream<ArtifactReference> stream = newArtifactStream( reference ))
{
return stream.filter( Objects::nonNull )
.map( ar -> ar.getVersion( ) )
private ArtifactReference getFirstArtifact( VersionedReference reference )
throws ContentNotFoundException, LayoutException, IOException
{
- try(Stream<ArtifactReference> stream = getArtifactStream( reference ))
+ try(Stream<ArtifactReference> stream = newArtifactStream( reference ))
{
return stream.findFirst( ).orElse( null );
} catch (RuntimeException e) {
}
}
- private Stream<ArtifactReference> getArtifactStream(VersionedReference reference) throws ContentNotFoundException, LayoutException, IOException {
+ private Stream<ArtifactReference> newArtifactStream( VersionedReference reference) throws ContentNotFoundException, LayoutException, IOException {
final Path repoBase = getRepoDir( );
String path = toMetadataPath( reference );
Path versionDir = repoBase.resolve( path ).getParent();
public List<ArtifactReference> getArtifacts(VersionedReference reference) throws ContentNotFoundException, LayoutException, ContentAccessException
{
- try (Stream<ArtifactReference> stream = getArtifactStream( reference ))
+ try (Stream<ArtifactReference> stream = newArtifactStream( reference ))
{
return stream.collect( Collectors.toList( ) );
} catch ( IOException e )
private boolean hasArtifact( VersionedReference reference )
{
- try(Stream<ArtifactReference> stream = getArtifactStream( reference ))
+ try(Stream<ArtifactReference> stream = newArtifactStream( reference ))
{
return stream.anyMatch( e -> true );
} catch (ContentNotFoundException e) {