Adding selector interface for repository content

This commit is contained in:
Martin Stockhammer 2020-02-13 22:20:35 +01:00
parent 84d9f5723f
commit 6823bb0371
19 changed files with 564 additions and 12 deletions

View File

@ -21,6 +21,7 @@ package org.apache.archiva.repository;
import org.apache.archiva.model.ArtifactReference;
import org.apache.archiva.model.VersionedReference;
import org.apache.archiva.repository.content.ItemSelector;
/**
@ -48,4 +49,12 @@ public interface RepositoryContent
* @return the relative path to the artifact.
*/
String toPath( ArtifactReference reference );
/**
* Return the path, that represents the item specified by the selector.
* @param selector the selector with the artifact coordinates
* @return the path to the content item
*/
String toPath( ItemSelector selector );
}

View File

@ -19,11 +19,8 @@ package org.apache.archiva.repository.content;
* under the License.
*/
import org.apache.archiva.repository.UnsupportedRepositoryTypeException;
import org.apache.archiva.repository.storage.StorageAsset;
import java.util.Map;
/**
*
* Represents a artifact of a repository. This object contains unique coordinates of the

View File

@ -0,0 +1,79 @@
package org.apache.archiva.repository.content;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
/**
* The item selector is used to specify coordinates for retrieving ContentItem elements.
*/
public interface ItemSelector
{
String getProjectId();
String getNamespace();
String getVersion( );
String getArtifactVersion();
String getArtifactId( );
String getType();
String getClassifier();
String getAttribute( String key );
Map<String, String> getAttributes( );
default boolean hasNamespace() {
return !StringUtils.isEmpty( getNamespace( ) );
}
default boolean hasProjectId() {
return !StringUtils.isEmpty( getProjectId( ) );
}
default boolean hasVersion() {
return !StringUtils.isEmpty(getVersion());
}
default boolean hasArtifactId() {
return !StringUtils.isEmpty( getArtifactId( ) );
}
default boolean hasArtifactVersion() {
return !StringUtils.isEmpty( getArtifactVersion( ) );
}
default boolean hasType() {
return !StringUtils.isEmpty( getType( ) );
}
default boolean hasClassifier() {
return !StringUtils.isEmpty( getClassifier( ) );
}
boolean hasAttributes();
}

View File

@ -19,7 +19,7 @@ package org.apache.archiva.repository.content;
* under the License.
*/
import org.apache.archiva.repository.ManagedRepositoryContent;
import org.apache.archiva.repository.RepositoryContent;
import org.apache.archiva.repository.storage.StorageAsset;
/**
@ -57,7 +57,7 @@ public interface Project extends ContentItem
* The repository this project is part of.
* @return the repository content
*/
ManagedRepositoryContent getRepository();
RepositoryContent getRepository();
/**
* Returns the asset that corresponds to this project.

View File

@ -0,0 +1,194 @@
package org.apache.archiva.repository.content.base;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.archiva.repository.content.ItemSelector;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Item selector for querying artifacts and other content items.
*/
public class ArchivaItemSelector implements ItemSelector
{
private String projectId = null;
private String version = null;
private String artifactVersion = null;
private String artifactId = null;
private String namespace = "";
private String type = null;
private String classifier = null;
private Map<String,String> attributes;
private ArchivaItemSelector() {
}
public static Builder builder() {
return new Builder();
}
public static class Builder
{
private final ArchivaItemSelector selector = new ArchivaItemSelector( );
public Builder withNamespace( String namespace )
{
selector.namespace = namespace;
return this;
}
public Builder withProjectId( String projectId )
{
selector.projectId = projectId;
return this;
}
public Builder withVersion( String version )
{
selector.version = version;
return this;
}
public Builder withArtifactVersion( String artifactVersion )
{
selector.artifactVersion = artifactVersion;
return this;
}
public Builder withArtifactId( String artifactId )
{
selector.artifactId = artifactId;
return this;
}
public Builder withType( String type )
{
selector.type = type;
return this;
}
public Builder withClassifier( String classifier )
{
selector.classifier = classifier;
return this;
}
public Builder withAttribute( String key, String value )
{
selector.setAttribute( key, value );
return this;
}
public ArchivaItemSelector build() {
return selector;
}
}
private void setAttribute(String key, String value) {
if (this.attributes == null) {
this.attributes = new HashMap<>( );
}
this.attributes.put( key, value );
}
@Override
public String getProjectId( )
{
return projectId;
}
@Override
public String getNamespace( )
{
return namespace;
}
@Override
public String getVersion( )
{
return version;
}
@Override
public String getArtifactVersion( )
{
return artifactVersion;
}
@Override
public String getArtifactId( )
{
return artifactId;
}
@Override
public String getType( )
{
return type;
}
@Override
public String getClassifier( )
{
return classifier;
}
@Override
public String getAttribute( String key )
{
if ( this.attributes == null || !this.attributes.containsKey( key ) )
{
return "";
}
else
{
return this.attributes.get( key );
}
}
@Override
public Map<String, String> getAttributes( )
{
if (this.attributes==null) {
return Collections.emptyMap( );
} else {
return Collections.unmodifiableMap( this.attributes );
}
}
@Override
public boolean hasAttributes( )
{
return attributes!=null && attributes.size()>0;
}
}

View File

@ -19,7 +19,9 @@ package org.apache.archiva.repository.content.base;
* under the License.
*/
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.ManagedRepositoryContent;
import org.apache.archiva.repository.RepositoryContent;
import org.apache.archiva.repository.content.Project;
import org.apache.archiva.repository.storage.StorageAsset;
import org.apache.commons.lang3.StringUtils;
@ -31,7 +33,7 @@ public class ArchivaProject extends ArchivaContentItem implements Project
{
private String namespace;
private String id;
private ManagedRepositoryContent repositoryContent;
private RepositoryContent repositoryContent;
private StorageAsset asset;
// Setting all setters to private. Builder is the way to go.
@ -63,7 +65,7 @@ public class ArchivaProject extends ArchivaContentItem implements Project
}
@Override
public ManagedRepositoryContent getRepository( )
public RepositoryContent getRepository( )
{
return this.repositoryContent;
}
@ -110,7 +112,7 @@ public class ArchivaProject extends ArchivaContentItem implements Project
}
public OptBuilder withRepository( ManagedRepositoryContent repository ) {
public OptBuilder withRepository( RepositoryContent repository ) {
project.repositoryContent = repository;
return this;
}
@ -140,7 +142,10 @@ public class ArchivaProject extends ArchivaContentItem implements Project
project.namespace = "";
}
if (project.asset == null) {
project.asset = project.getRepository( ).getRepository( ).getAsset( "" );
if (project.getRepository() instanceof ManagedRepositoryContent) {
project.asset = (( ManagedRepositoryContent)project.getRepository( )).getRepository( ).getAsset( "" );
}
}
return project;
}

View File

@ -95,7 +95,7 @@ public class ArchivaVersion extends ArchivaContentItem implements Version
public ArchivaVersion build() {
if (this.version.asset == null) {
this.version.project.getRepository( ).getRepository().getAsset( "" );
this.version.project.getAsset( );
}
return this.version;
}

View File

@ -0,0 +1,145 @@
package org.apache.archiva.repository.content.base;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class ArchivaItemSelectorTest
{
@Test
void getProjectId( )
{
ArchivaItemSelector selector = ArchivaItemSelector.builder( ).withProjectId( "test-project-123" ).build( );
assertEquals( "test-project-123", selector.getProjectId( ) );
assertTrue( selector.hasProjectId( ) );
assertFalse( selector.hasVersion( ) );
assertFalse( selector.hasArtifactId( ) );
assertFalse( selector.hasArtifactVersion( ) );
assertFalse( selector.hasType( ) );
assertFalse( selector.hasClassifier( ) );
assertFalse( selector.hasAttributes( ) );
}
@Test
void getNamespace( )
{
ArchivaItemSelector selector = ArchivaItemSelector.builder( ).withNamespace( "abc.de.fg" ).build();
assertEquals( "abc.de.fg", selector.getNamespace( ) );
assertFalse( selector.hasProjectId( ) );
assertFalse( selector.hasVersion( ) );
assertFalse( selector.hasArtifactId( ) );
assertFalse( selector.hasArtifactVersion( ) );
assertFalse( selector.hasType( ) );
assertFalse( selector.hasClassifier( ) );
assertFalse( selector.hasAttributes( ) );
}
@Test
void getVersion( )
{
ArchivaItemSelector selector = ArchivaItemSelector.builder( ).withVersion( "1.15.20.3" ).build();
assertEquals( "1.15.20.3", selector.getVersion( ) );
assertFalse( selector.hasProjectId( ) );
assertTrue( selector.hasVersion( ) );
assertFalse( selector.hasArtifactId( ) );
assertFalse( selector.hasArtifactVersion( ) );
assertFalse( selector.hasType( ) );
assertFalse( selector.hasClassifier( ) );
assertFalse( selector.hasAttributes( ) );
}
@Test
void getArtifactVersion( )
{
ArchivaItemSelector selector = ArchivaItemSelector.builder( ).withArtifactVersion( "5.13.2.4" ).build();
assertEquals( "5.13.2.4", selector.getArtifactVersion() );
assertFalse( selector.hasProjectId( ) );
assertFalse( selector.hasVersion( ) );
assertFalse( selector.hasArtifactId( ) );
assertTrue( selector.hasArtifactVersion( ) );
assertFalse( selector.hasType( ) );
assertFalse( selector.hasClassifier( ) );
assertFalse( selector.hasAttributes( ) );
}
@Test
void getArtifactId( )
{
ArchivaItemSelector selector = ArchivaItemSelector.builder( ).withArtifactId( "xml-tools" ).build();
assertEquals( "xml-tools", selector.getArtifactId() );
assertFalse( selector.hasProjectId( ) );
assertFalse( selector.hasVersion( ) );
assertTrue( selector.hasArtifactId( ) );
assertFalse( selector.hasArtifactVersion( ) );
assertFalse( selector.hasType( ) );
assertFalse( selector.hasClassifier( ) );
assertFalse( selector.hasAttributes( ) );
}
@Test
void getType( )
{
ArchivaItemSelector selector = ArchivaItemSelector.builder( ).withType( "javadoc" ).build();
assertEquals( "javadoc", selector.getType() );
assertFalse( selector.hasProjectId( ) );
assertFalse( selector.hasVersion( ) );
assertFalse( selector.hasArtifactId( ) );
assertFalse( selector.hasArtifactVersion( ) );
assertTrue( selector.hasType( ) );
assertFalse( selector.hasClassifier( ) );
assertFalse( selector.hasAttributes( ) );
}
@Test
void getClassifier( )
{
ArchivaItemSelector selector = ArchivaItemSelector.builder( ).withClassifier( "source" ).build();
assertEquals( "source", selector.getClassifier() );
assertFalse( selector.hasProjectId( ) );
assertFalse( selector.hasVersion( ) );
assertFalse( selector.hasArtifactId( ) );
assertFalse( selector.hasArtifactVersion( ) );
assertFalse( selector.hasType( ) );
assertTrue( selector.hasClassifier( ) );
assertFalse( selector.hasAttributes( ) );
}
@Test
void getAttribute( )
{
ArchivaItemSelector selector = ArchivaItemSelector.builder( ).withAttribute( "test1","value1" ).
withAttribute( "test2", "value2" ).build();
assertEquals( "value1", selector.getAttribute("test1") );
assertEquals( "value2", selector.getAttribute("test2") );
assertFalse( selector.hasProjectId( ) );
assertFalse( selector.hasVersion( ) );
assertFalse( selector.hasArtifactId( ) );
assertFalse( selector.hasArtifactVersion( ) );
assertFalse( selector.hasType( ) );
assertFalse( selector.hasClassifier( ) );
assertTrue( selector.hasAttributes( ) );
}
}

View File

@ -28,6 +28,7 @@ import org.apache.archiva.repository.ContentNotFoundException;
import org.apache.archiva.repository.LayoutException;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.ManagedRepositoryContent;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.archiva.repository.storage.StorageAsset;
import org.springframework.stereotype.Service;
@ -216,6 +217,12 @@ public class ManagedRepositoryContentMock implements ManagedRepositoryContent
return null;
}
@Override
public String toPath( ItemSelector selector )
{
return null;
}
@Override
public String toPath( ArchivaArtifact reference )
{

View File

@ -24,6 +24,7 @@ import org.apache.archiva.model.RepositoryURL;
import org.apache.archiva.repository.LayoutException;
import org.apache.archiva.repository.RemoteRepository;
import org.apache.archiva.repository.RemoteRepositoryContent;
import org.apache.archiva.repository.content.ItemSelector;
import org.springframework.stereotype.Service;
/**
@ -70,6 +71,12 @@ public class RemoteRepositoryContentMock implements RemoteRepositoryContent
return null;
}
@Override
public String toPath( ItemSelector selector )
{
return null;
}
@Override
public RepositoryURL toURL( ArtifactReference reference )
{

View File

@ -28,6 +28,7 @@ import org.apache.archiva.model.ArtifactReference;
import org.apache.archiva.model.ProjectReference;
import org.apache.archiva.model.VersionedReference;
import org.apache.archiva.repository.*;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.archiva.repository.storage.FilesystemStorage;
import org.apache.archiva.repository.storage.StorageAsset;
import org.apache.commons.lang3.StringUtils;
@ -446,6 +447,12 @@ public class ManagedRepositoryContentMock implements ManagedRepositoryContent
return null;
}
@Override
public String toPath( ItemSelector selector )
{
return null;
}
@Override
public String toPath( ArchivaArtifact reference )
{

View File

@ -28,6 +28,7 @@ import org.apache.archiva.model.ArtifactReference;
import org.apache.archiva.model.ProjectReference;
import org.apache.archiva.model.VersionedReference;
import org.apache.archiva.repository.*;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.archiva.repository.storage.FilesystemStorage;
import org.apache.archiva.repository.storage.RepositoryStorage;
import org.apache.archiva.repository.storage.StorageAsset;
@ -450,6 +451,12 @@ public class ManagedRepositoryContentMock implements ManagedRepositoryContent
return null;
}
@Override
public String toPath( ItemSelector selector )
{
return null;
}
@Override
public String toPath( ArchivaArtifact reference )
{

View File

@ -25,6 +25,7 @@ import org.apache.archiva.model.RepositoryURL;
import org.apache.archiva.repository.LayoutException;
import org.apache.archiva.repository.RemoteRepository;
import org.apache.archiva.repository.RemoteRepositoryContent;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
@ -84,6 +85,20 @@ public class RemoteRepositoryContentMock implements RemoteRepositoryContent
StringUtils.isNotEmpty(reference.getClassifier()) ? "-"+reference.getClassifier() : "")+"."+reference.getType();
}
@Override
public String toPath( ItemSelector selector )
{
String baseVersion;
if (!selector.hasVersion() && VersionUtil.isSnapshot(selector.getArtifactVersion())) {
baseVersion=VersionUtil.getBaseVersion(selector.getArtifactVersion());
} else {
baseVersion=selector.getVersion();
}
return selector.getNamespace().replaceAll("\\.", "/")+"/"+selector.getArtifactId()+"/"+baseVersion+"/"
+selector.getArtifactId()+"-"+selector.getVersion()+(
StringUtils.isNotEmpty(selector.getClassifier()) ? "-"+selector.getClassifier() : "")+"."+selector.getType();
}
@Override
public RepositoryURL toURL( ArtifactReference reference )
{

View File

@ -24,6 +24,7 @@ import org.apache.archiva.metadata.model.ArtifactMetadata;
import org.apache.archiva.metadata.model.maven2.MavenArtifactFacet;
import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
import org.apache.archiva.repository.storage.StorageAsset;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@ -140,12 +141,17 @@ public class Maven2RepositoryPathTranslator
private void appendNamespaceAndProject( StringBuilder path, String namespace, String projectId )
{
appendNamespace( path, namespace );
path.append( projectId ).append( PATH_SEPARATOR );
if (StringUtils.isNotEmpty( projectId ))
{
path.append( projectId ).append( PATH_SEPARATOR );
}
}
private void appendNamespace( StringBuilder path, String namespace )
{
path.append( formatAsDirectory( namespace ) ).append( PATH_SEPARATOR );
if ( StringUtils.isNotEmpty( namespace ) ) {
path.append( formatAsDirectory( namespace ) ).append( PATH_SEPARATOR );
}
}
@Override

View File

@ -29,7 +29,9 @@ import org.apache.archiva.model.ProjectReference;
import org.apache.archiva.model.VersionedReference;
import org.apache.archiva.repository.LayoutException;
import org.apache.archiva.repository.RepositoryContent;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.archiva.repository.content.PathParser;
import org.apache.archiva.repository.content.Version;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -86,6 +88,45 @@ public abstract class AbstractDefaultRepositoryContent implements RepositoryCont
return path.toString( );
}
@Override
public String toPath ( ItemSelector selector ) {
if (selector==null) {
throw new IllegalArgumentException( "ItemSelector must not be null." );
}
String projectId;
// Initialize the project id if not set
if (selector.hasProjectId()) {
projectId = selector.getProjectId( );
} else if (selector.hasArtifactId()) {
// projectId same as artifact id, if set
projectId = selector.getArtifactId( );
} else {
// we arrive here, if projectId && artifactId not set
return pathTranslator.toPath( selector.getNamespace(), "");
}
if ( !selector.hasArtifactId( )) {
return pathTranslator.toPath( selector.getNamespace( ), projectId );
}
// this part only, if projectId && artifactId is set
String artifactVersion = "";
String version = "";
if (selector.hasVersion() && selector.hasArtifactVersion() ) {
artifactVersion = selector.getArtifactVersion();
version = VersionUtil.getBaseVersion( selector.getVersion( ) );
} else if (!selector.hasVersion() && selector.hasArtifactVersion()) {
// we try to retrieve the base version, if artifact version is only set
version = VersionUtil.getBaseVersion( selector.getArtifactVersion( ) );
artifactVersion = selector.getArtifactVersion( );
} else if (selector.hasVersion() && !selector.hasArtifactVersion()) {
artifactVersion = selector.getVersion();
version = VersionUtil.getBaseVersion( selector.getVersion( ) );
}
return pathTranslator.toPath( selector.getNamespace(), projectId, version,
constructId( selector.getArtifactId(), artifactVersion, selector.getClassifier(), selector.getType() ) );
}
public String toMetadataPath( ProjectReference reference )
{
final StringBuilder path = new StringBuilder();

View File

@ -34,6 +34,7 @@ import org.apache.archiva.repository.EditableManagedRepository;
import org.apache.archiva.repository.LayoutException;
import org.apache.archiva.repository.ManagedRepository;
import org.apache.archiva.repository.ManagedRepositoryContent;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.archiva.repository.storage.StorageAsset;
import org.apache.commons.lang3.StringUtils;
@ -572,6 +573,7 @@ public class ManagedDefaultRepositoryContent
}
}
// The variant with runtime exception for stream usage
private ArtifactReference toArtifactRef(String path) {
try {

View File

@ -22,6 +22,7 @@ package org.apache.archiva.metadata.repository.storage.maven2;
import org.apache.archiva.model.ArtifactReference;
import org.apache.archiva.repository.AbstractRepositoryLayerTestCase;
import org.apache.archiva.repository.LayoutException;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
@ -415,6 +416,21 @@ public abstract class AbstractDefaultRepositoryContentTestCase
}
}
public void testToPathOnNullItemSelector()
{
try
{
ItemSelector selector = null;
toPath( selector );
fail( "Should have failed due to null artifact reference." );
}
catch ( IllegalArgumentException e )
{
/* expected path */
}
}
private void assertArtifactReference( ArtifactReference actualReference, String groupId, String artifactId,
String version, String classifier, String type )
{
@ -488,4 +504,7 @@ public abstract class AbstractDefaultRepositoryContentTestCase
throws LayoutException;
protected abstract String toPath( ArtifactReference reference );
protected abstract String toPath( ItemSelector selector );
}

View File

@ -29,6 +29,7 @@ import org.apache.archiva.model.ProjectReference;
import org.apache.archiva.model.VersionedReference;
import org.apache.archiva.repository.EditableManagedRepository;
import org.apache.archiva.repository.LayoutException;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.archiva.repository.content.maven2.ManagedDefaultRepositoryContent;
import org.apache.archiva.repository.maven2.MavenManagedRepository;
import org.apache.commons.io.FileUtils;
@ -259,6 +260,11 @@ public class ManagedDefaultRepositoryContentTest
return repoContent.toPath( reference );
}
@Override
protected String toPath( ItemSelector selector ) {
return repoContent.toPath( selector );
}
private Path setupRepoCopy( String source, String target) throws IOException
{
Path defaultRepo = getRepositoryPath( source );

View File

@ -23,6 +23,7 @@ import org.apache.archiva.model.ArtifactReference;
import org.apache.archiva.repository.LayoutException;
import org.apache.archiva.repository.RemoteRepository;
import org.apache.archiva.repository.RemoteRepositoryContent;
import org.apache.archiva.repository.content.ItemSelector;
import org.apache.archiva.repository.content.maven2.RemoteDefaultRepositoryContent;
import org.junit.Before;
@ -65,4 +66,9 @@ public class RemoteDefaultRepositoryContentTest
{
return repoContent.toPath( reference );
}
@Override
protected String toPath( ItemSelector selector ) {
return repoContent.toPath( selector );
}
}