aboutsummaryrefslogtreecommitdiffstats
path: root/archiva-modules/archiva-base/archiva-repository-layer
diff options
context:
space:
mode:
authorMartin Stockhammer <martin_s@apache.org>2020-05-24 18:18:37 +0200
committerMartin Stockhammer <martin_s@apache.org>2020-05-30 20:00:22 +0200
commitac25c7a86fe77f5b0f005f03d9d28dc1f6f8580e (patch)
treed6f1650edea83a7ed04c1ae40cf8e03d70ff8ed0 /archiva-modules/archiva-base/archiva-repository-layer
parent56de9e590b8d040add03b99df2e221eeedde860e (diff)
downloadarchiva-ac25c7a86fe77f5b0f005f03d9d28dc1f6f8580e.tar.gz
archiva-ac25c7a86fe77f5b0f005f03d9d28dc1f6f8580e.zip
Changing content item API
Diffstat (limited to 'archiva-modules/archiva-base/archiva-repository-layer')
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaArtifact.java6
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaContentItem.java168
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaDataItem.java28
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaNamespace.java5
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaProject.java15
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaVersion.java15
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/BaseContentItem.java151
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ContentItemBuilder.java103
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/builder/ArchivaContentItemOptBuilder.java38
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/builder/DataItemOptBuilder.java2
-rw-r--r--archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/mock/ManagedRepositoryContentMock.java24
11 files changed, 380 insertions, 175 deletions
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaArtifact.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaArtifact.java
index 26b0449ba..b65fa7400 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaArtifact.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaArtifact.java
@@ -22,8 +22,6 @@ package org.apache.archiva.repository.content.base;
import org.apache.archiva.repository.content.Artifact;
import org.apache.archiva.repository.content.ArtifactType;
import org.apache.archiva.repository.content.BaseArtifactTypes;
-import org.apache.archiva.repository.content.ContentItem;
-import org.apache.archiva.repository.content.DataItem;
import org.apache.archiva.repository.content.Version;
import org.apache.archiva.repository.content.base.builder.ArtifactOptBuilder;
import org.apache.archiva.repository.content.base.builder.ArtifactVersionBuilder;
@@ -52,7 +50,7 @@ import org.apache.commons.lang3.StringUtils;
*
* @author Martin Stockhammer <martin_s@apache.org>
*/
-public class ArchivaArtifact extends ArchivaContentItem implements Artifact
+public class ArchivaArtifact extends BaseContentItem implements Artifact
{
private String id;
private String artifactVersion;
@@ -135,8 +133,6 @@ public class ArchivaArtifact extends ArchivaContentItem implements Artifact
{
if ( this == o ) return true;
if ( o == null || getClass( ) != o.getClass( ) ) return false;
- if ( !super.equals( o ) ) return false;
-
ArchivaArtifact that = (ArchivaArtifact) o;
if ( !id.equals( that.id ) ) return false;
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaContentItem.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaContentItem.java
index 7e15d61be..acba93b4f 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaContentItem.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaContentItem.java
@@ -21,105 +21,39 @@ package org.apache.archiva.repository.content.base;
import org.apache.archiva.repository.ManagedRepositoryContent;
import org.apache.archiva.repository.content.ContentItem;
+import org.apache.archiva.repository.content.Namespace;
import org.apache.archiva.repository.content.Project;
-import org.apache.archiva.repository.content.base.builder.OptBuilder;
+import org.apache.archiva.repository.content.Version;
+import org.apache.archiva.repository.content.base.builder.ArchivaContentItemOptBuilder;
import org.apache.archiva.repository.content.base.builder.WithAssetBuilder;
-import org.apache.archiva.repository.content.base.builder.WithRepositoryBuilder;
import org.apache.archiva.repository.storage.StorageAsset;
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
/**
* Abstract implementation of ContentItem interface.
* <p>
* The attribute map is created, when the first values are put to the map.
*/
-public abstract class ArchivaContentItem implements ContentItem
+public class ArchivaContentItem extends BaseContentItem implements ContentItem
{
- private Map<String, String> attributes;
- private ManagedRepositoryContent repository;
- private StorageAsset asset;
-
- @Override
- public <T extends Project> T adapt( Class<T> clazz )
- {
- return (T) this;
- }
-
- @Override
- public <T extends Project> boolean supports( Class<T> clazz )
- {
- return clazz != null && clazz.isAssignableFrom( this.getClass( ) );
- }
-
-
- /**
- * Does lazy initialization of the attributes map.
- * Returns a unmodifiable map.
- *
- * @return unmodifiable map of attributes
- */
- @Override
- public Map<String, String> getAttributes( )
- {
- if ( this.attributes == null )
- {
- return Collections.emptyMap( );
- }
- else
- {
- return Collections.unmodifiableMap( this.attributes );
- }
- }
/**
- * Adds a attribute value. The key must not be <code>null</code>.
+ * Creates the builder for creating new archiva project instances.
+ * You have to set all required attributes before you can call the build() method.
*
- * @param key the attribute key
- * @param value the attribute value
- * @throws IllegalArgumentException if the key is <code>null</code> or empty
+ * @param storageAsset the asset
+ * @return a builder instance
*/
- public void putAttribute( String key, String value ) throws IllegalArgumentException
- {
- if ( this.attributes == null )
- {
- this.attributes = new HashMap<>( );
- }
- if ( StringUtils.isEmpty( key ) )
- {
- throw new IllegalArgumentException( "Key value must not be empty or null" );
- }
- this.attributes.put( key, value );
- }
-
- @Override
- public String getAttribute( String key )
+ public static ArchivaContentItemOptBuilder withAsset( StorageAsset storageAsset )
{
- if ( this.attributes == null )
- {
- return null;
- }
- else
- {
- return this.attributes.get( key );
- }
+ return new ArchivaContentItemBuilder().withAsset( storageAsset );
}
- @Override
- public ManagedRepositoryContent getRepository( )
+ public static WithAssetBuilder<ArchivaContentItemOptBuilder> withRepository( ManagedRepositoryContent repository )
{
- return repository;
+ return new ArchivaContentItemBuilder().withRepository( repository );
}
- @Override
- public StorageAsset getAsset( )
- {
- return asset;
- }
@Override
public boolean equals( Object o )
@@ -150,86 +84,56 @@ public abstract class ArchivaContentItem implements ContentItem
*/
- /**
- * Builder for content item. Must be extended by subclasses.
- * The builder uses chained interfaces for building the required attributes. That means you have to set
- * some certain attributes, before you can build the content item instance via the {@link #build()} method.
- * <p>
- * Subclasses should extend from this class and provide the interface/class for the destination item,
- * a interface for the optional attributes and a interface that is returned after the last required attribute is
- * set.
- * <p>
- * The interface for optional attributes should inherit from {@link OptBuilder}
- *
- * @param <I> the item class that should be built
- * @param <O> the class/interface for the optional attributes
- * @param <N> the class/interface for the next (required) attribute after the base attributes are set
- */
- protected abstract static class ContentItemBuilder<I extends ArchivaContentItem, O extends OptBuilder<I, O>, N>
- implements WithRepositoryBuilder, WithAssetBuilder<N>,
- OptBuilder<I, O>
+ public static final class ArchivaContentItemBuilder extends ContentItemBuilder<ArchivaContentItem, ArchivaContentItemOptBuilder, ArchivaContentItemOptBuilder>
+ implements ArchivaContentItemOptBuilder
{
- protected I item;
-
- protected ContentItemBuilder( I item )
+ private ArchivaContentItemBuilder( )
{
- this.item = item;
+ super( new ArchivaContentItem() );
}
- protected abstract O getOptBuilder( );
-
- protected abstract N getNextBuilder( );
+ @Override
+ public ArchivaContentItemOptBuilder getOptBuilder( )
+ {
+ return this;
+ }
@Override
- public WithAssetBuilder<N> withRepository( ManagedRepositoryContent repository )
+ public ArchivaContentItemOptBuilder getNextBuilder( )
{
- if ( repository == null )
- {
- throw new IllegalArgumentException( "Repository may not be null" );
- }
- ( (ArchivaContentItem) item ).repository = repository;
return this;
}
+
@Override
- public N withAsset( StorageAsset asset )
+ public ArchivaContentItemOptBuilder withNamespace( Namespace namespace )
{
- if ( asset == null )
- {
- throw new IllegalArgumentException( "Asset may not be null" );
- }
- ( (ArchivaContentItem) item ).asset = asset;
- return getNextBuilder( );
+ item.setCharacteristic( Namespace.class, namespace );
+ return this;
}
@Override
- public O withAttribute( String key, String value )
+ public ArchivaContentItemOptBuilder withProject( Project project )
{
- if ( StringUtils.isEmpty( key ) )
- {
- throw new IllegalArgumentException( "Attribute key may not be null" );
- }
- item.putAttribute( key, value );
- return getOptBuilder( );
+ item.setCharacteristic( Project.class, project );
+ return this;
}
- protected void setRepository( ManagedRepositoryContent repository )
+ @Override
+ public ArchivaContentItemOptBuilder withVersion( Version version )
{
- ( (ArchivaContentItem) item ).repository = repository;
+ item.setCharacteristic( Version.class, version );
+ return this;
}
@Override
- public I build( )
+ public ArchivaContentItem build( )
{
+ super.build( );
return item;
}
-
}
- @Override
- public boolean exists( )
- {
- return asset.exists( );
- }
+
}
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaDataItem.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaDataItem.java
index cb13e1832..c825bb316 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaDataItem.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaDataItem.java
@@ -19,9 +19,7 @@ package org.apache.archiva.repository.content.base;
* under the License.
*/
-import org.apache.archiva.repository.content.BaseArtifactTypes;
import org.apache.archiva.repository.content.BaseDataItemTypes;
-import org.apache.archiva.repository.content.ContentItem;
import org.apache.archiva.repository.content.DataItem;
import org.apache.archiva.repository.content.DataItemType;
import org.apache.archiva.repository.content.base.builder.DataItemOptBuilder;
@@ -49,10 +47,9 @@ import org.apache.commons.lang3.StringUtils;
*
* @author Martin Stockhammer <martin_s@apache.org>
*/
-public class ArchivaDataItem extends ArchivaContentItem implements DataItem
+public class ArchivaDataItem extends BaseContentItem implements DataItem
{
private String id;
- private ContentItem parent;
private String contentType;
private DataItemType dataItemType;
@@ -68,12 +65,6 @@ public class ArchivaDataItem extends ArchivaContentItem implements DataItem
}
@Override
- public ContentItem getParent( )
- {
- return parent;
- }
-
- @Override
public String getContentType( )
{
return contentType;
@@ -109,7 +100,6 @@ public class ArchivaDataItem extends ArchivaContentItem implements DataItem
ArchivaDataItem that = (ArchivaDataItem) o;
if ( !id.equals( that.id ) ) return false;
- if ( !parent.equals( that.parent ) ) return false;
return dataItemType.equals(that.dataItemType );
}
@@ -118,7 +108,6 @@ public class ArchivaDataItem extends ArchivaContentItem implements DataItem
{
int result = super.hashCode( );
result = 31 * result + id.hashCode( );
- result = 31 * result + parent.hashCode( );
result = 31 * result + dataItemType.hashCode( );
return result;
}
@@ -126,9 +115,8 @@ public class ArchivaDataItem extends ArchivaContentItem implements DataItem
@Override
public String toString( )
{
- final StringBuilder sb = new StringBuilder( "ArchivaArtifact{" );
+ final StringBuilder sb = new StringBuilder( "ArchivaDataItem{" );
sb.append( "id='" ).append( id ).append( '\'' );
- sb.append( ", parent=" ).append( parent );
sb.append( ", contentType='" ).append( contentType ).append( '\'' );
sb.append( ", artifactType=" ).append( dataItemType );
sb.append( '}' );
@@ -168,18 +156,6 @@ public class ArchivaDataItem extends ArchivaContentItem implements DataItem
}
@Override
- public DataItemOptBuilder withParent( ContentItem parent )
- {
- if ( parent == null )
- {
- throw new IllegalArgumentException( "version may not be null" );
- }
- item.parent = parent;
- super.setRepository( parent.getRepository( ) );
- return this;
- }
-
- @Override
public DataItemOptBuilder withId( String id )
{
if ( StringUtils.isEmpty( id ) )
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaNamespace.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaNamespace.java
index b85f25a60..9982ea0de 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaNamespace.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaNamespace.java
@@ -38,7 +38,7 @@ import java.util.regex.PatternSyntaxException;
* @author Martin Stockhammer <martin_s@apache.org>
* @since 3.0
*/
-public class ArchivaNamespace extends ArchivaContentItem implements Namespace
+public class ArchivaNamespace extends BaseContentItem implements Namespace
{
private String namespace;
private List<String> namespacePath;
@@ -72,10 +72,9 @@ public class ArchivaNamespace extends ArchivaContentItem implements Namespace
{
if ( this == o ) return true;
if ( o == null || getClass( ) != o.getClass( ) ) return false;
- if ( !super.equals( o ) ) return false;
-
ArchivaNamespace that = (ArchivaNamespace) o;
+ if (!repository.equals( that.repository )) return false;
return namespace.equals( that.namespace );
}
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaProject.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaProject.java
index ac72f6217..9fb9a0cf6 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaProject.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaProject.java
@@ -19,11 +19,15 @@ package org.apache.archiva.repository.content.base;
* under the License.
*/
+import org.apache.archiva.repository.ManagedRepositoryContent;
import org.apache.archiva.repository.content.Namespace;
import org.apache.archiva.repository.content.Project;
import org.apache.archiva.repository.content.base.builder.ProjectOptBuilder;
import org.apache.archiva.repository.content.base.builder.ProjectWithIdBuilder;
+import org.apache.archiva.repository.content.base.builder.WithAssetBuilder;
+import org.apache.archiva.repository.content.base.builder.WithNamespaceBuilder;
import org.apache.archiva.repository.content.base.builder.WithNamespaceObjectBuilder;
+import org.apache.archiva.repository.content.base.builder.WithProjectBuilder;
import org.apache.archiva.repository.storage.StorageAsset;
import org.apache.commons.lang3.StringUtils;
@@ -38,7 +42,7 @@ import org.apache.commons.lang3.StringUtils;
* @author Martin Stockhammer <martin_s@apache.org>
* @since 3.0
*/
-public class ArchivaProject extends ArchivaContentItem implements Project
+public class ArchivaProject extends BaseContentItem implements Project
{
private Namespace namespace;
private String id;
@@ -62,6 +66,11 @@ public class ArchivaProject extends ArchivaContentItem implements Project
return new Builder( ).withAsset( storageAsset );
}
+ public static WithAssetBuilder<WithNamespaceObjectBuilder> withRepository( ManagedRepositoryContent repository )
+ {
+ return new ArchivaProject.Builder( ).withRepository( repository );
+ }
+
@Override
public Namespace getNamespace( )
{
@@ -80,10 +89,10 @@ public class ArchivaProject extends ArchivaContentItem implements Project
{
if ( this == o ) return true;
if ( o == null || getClass( ) != o.getClass( ) ) return false;
- if ( !super.equals( o ) ) return false;
ArchivaProject that = (ArchivaProject) o;
+ if (!repository.equals( that.repository )) return false;
if ( !namespace.equals( that.namespace ) ) return false;
return id.equals( that.id );
}
@@ -100,7 +109,7 @@ public class ArchivaProject extends ArchivaContentItem implements Project
@Override
public String toString( )
{
- return id + ", namespace="+namespace.toString();
+ return "ArchivaProject{ "+id + ", namespace="+namespace.toString()+"}";
}
/*
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaVersion.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaVersion.java
index e10d3b1c5..c553c3bfc 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaVersion.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ArchivaVersion.java
@@ -19,9 +19,12 @@ package org.apache.archiva.repository.content.base;
* under the License.
*/
+import org.apache.archiva.repository.ManagedRepositoryContent;
import org.apache.archiva.repository.content.Project;
import org.apache.archiva.repository.content.Version;
import org.apache.archiva.repository.content.base.builder.VersionOptBuilder;
+import org.apache.archiva.repository.content.base.builder.WithAssetBuilder;
+import org.apache.archiva.repository.content.base.builder.WithNamespaceBuilder;
import org.apache.archiva.repository.content.base.builder.WithProjectBuilder;
import org.apache.archiva.repository.content.base.builder.WithVersionBuilder;
import org.apache.archiva.repository.storage.StorageAsset;
@@ -41,7 +44,7 @@ import java.util.regex.PatternSyntaxException;
* <p>
* Two instances are equal, if the project and the version match in addition to the base attributes repository and asset.
*/
-public class ArchivaVersion extends ArchivaContentItem implements Version
+public class ArchivaVersion extends BaseContentItem implements Version
{
private String version;
@@ -66,6 +69,11 @@ public class ArchivaVersion extends ArchivaContentItem implements Version
return new Builder( ).withAsset( storageAsset );
}
+ public static WithAssetBuilder<WithProjectBuilder> withRepository( ManagedRepositoryContent repository )
+ {
+ return new ArchivaVersion.Builder( ).withRepository( repository );
+ }
+
@Override
public List<String> getVersionSegments( )
{
@@ -90,10 +98,9 @@ public class ArchivaVersion extends ArchivaContentItem implements Version
{
if ( this == o ) return true;
if ( o == null || getClass( ) != o.getClass( ) ) return false;
- if ( !super.equals( o ) ) return false;
ArchivaVersion that = (ArchivaVersion) o;
-
+ if (!repository.equals( that.repository )) return false;
if ( !version.equals( that.version ) ) return false;
return project.equals( that.project );
}
@@ -110,7 +117,7 @@ public class ArchivaVersion extends ArchivaContentItem implements Version
@Override
public String toString( )
{
- return version+", project="+project.toString();
+ return "ArchivaVersion{ "+version+", project="+project.toString()+"}";
}
private static final class Builder extends ContentItemBuilder<ArchivaVersion, VersionOptBuilder, WithProjectBuilder>
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/BaseContentItem.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/BaseContentItem.java
new file mode 100644
index 000000000..3866131ec
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/BaseContentItem.java
@@ -0,0 +1,151 @@
+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.ItemConversionException;
+import org.apache.archiva.repository.LayoutException;
+import org.apache.archiva.repository.ManagedRepositoryContent;
+import org.apache.archiva.repository.content.ContentItem;
+import org.apache.archiva.repository.storage.StorageAsset;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public abstract class BaseContentItem implements ContentItem
+{
+ protected ManagedRepositoryContent repository;
+ protected StorageAsset asset;
+ private Map<String, String> attributes;
+ private Map<Class<?>, ContentItem> characteristics = new HashMap<>( );
+ private Set<Class<?>> failedConversions = new HashSet<>( );
+
+ @Override
+ public <T extends ContentItem> T adapt( Class<T> clazz ) throws ItemConversionException
+ {
+ if (characteristics.containsKey( clazz )) {
+ return (T) characteristics.get( clazz );
+ } else {
+ for ( Map.Entry<Class<?>, ? extends ContentItem> cEntry : characteristics.entrySet()) {
+ if (clazz.isAssignableFrom( cEntry.getKey() )) {
+ return (T) cEntry.getValue( );
+ }
+ }
+ try {
+ return repository.applyCharacteristic( clazz, this );
+ } catch ( LayoutException e ) {
+ throw new ItemConversionException( "Could not convert item to " + clazz, e );
+ }
+ }
+ }
+
+ @Override
+ public <T extends ContentItem> boolean hasCharacteristic( Class<T> clazz )
+ {
+ if (clazz == null) {
+ return false;
+ }
+ if ( characteristics.containsKey( clazz )
+ || characteristics.keySet( ).stream( ).anyMatch( cClass -> clazz.isAssignableFrom( cClass ) ) ) {
+ return true;
+ };
+ return false;
+ }
+
+ /**
+ * Does lazy initialization of the attributes map.
+ * Returns a unmodifiable map.
+ *
+ * @return unmodifiable map of attributes
+ */
+ @Override
+ public Map<String, String> getAttributes( )
+ {
+ if ( this.attributes == null )
+ {
+ return Collections.emptyMap( );
+ }
+ else
+ {
+ return Collections.unmodifiableMap( this.attributes );
+ }
+ }
+
+ /**
+ * Adds a attribute value. The key must not be <code>null</code>.
+ *
+ * @param key the attribute key
+ * @param value the attribute value
+ * @throws IllegalArgumentException if the key is <code>null</code> or empty
+ */
+ public void putAttribute( String key, String value ) throws IllegalArgumentException
+ {
+ if ( this.attributes == null )
+ {
+ this.attributes = new HashMap<>( );
+ }
+ if ( StringUtils.isEmpty( key ) )
+ {
+ throw new IllegalArgumentException( "Key value must not be empty or null" );
+ }
+ this.attributes.put( key, value );
+ }
+
+ @Override
+ public String getAttribute( String key )
+ {
+ if ( this.attributes == null )
+ {
+ return null;
+ }
+ else
+ {
+ return this.attributes.get( key );
+ }
+ }
+
+ @Override
+ public ManagedRepositoryContent getRepository( )
+ {
+ return repository;
+ }
+
+ @Override
+ public StorageAsset getAsset( )
+ {
+ return asset;
+ }
+
+ @Override
+ public boolean exists( )
+ {
+ return asset.exists( );
+ }
+
+ public <T extends ContentItem> void setCharacteristic( Class<T> clazz, T item )
+ {
+ this.characteristics.put( clazz, item );
+ }
+}
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ContentItemBuilder.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ContentItemBuilder.java
new file mode 100644
index 000000000..dd3a53db7
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/ContentItemBuilder.java
@@ -0,0 +1,103 @@
+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.ManagedRepositoryContent;
+import org.apache.archiva.repository.content.base.builder.OptBuilder;
+import org.apache.archiva.repository.content.base.builder.WithAssetBuilder;
+import org.apache.archiva.repository.content.base.builder.WithRepositoryBuilder;
+import org.apache.archiva.repository.storage.StorageAsset;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Builder for content item. Must be extended by subclasses.
+ * The builder uses chained interfaces for building the required attributes. That means you have to set
+ * some certain attributes, before you can build the content item instance via the {@link #build()} method.
+ * <p>
+ * Subclasses should extend from this class and provide the interface/class for the destination item,
+ * a interface for the optional attributes and a interface that is returned after the last required attribute is
+ * set.
+ * <p>
+ * The interface for optional attributes should inherit from {@link OptBuilder}
+ *
+ * @param <I> the item class that should be built
+ * @param <O> the class/interface for the optional attributes
+ * @param <N> the class/interface for the next (required) attribute after the base attributes are set
+ */
+abstract class ContentItemBuilder<I extends BaseContentItem, O extends OptBuilder<I, O>, N>
+ implements WithRepositoryBuilder, WithAssetBuilder<N>,
+ OptBuilder<I, O>
+{
+
+ protected I item;
+
+ protected ContentItemBuilder( I item )
+ {
+ this.item = item;
+ }
+
+ protected abstract O getOptBuilder( );
+
+ protected abstract N getNextBuilder( );
+
+ @Override
+ public WithAssetBuilder<N> withRepository( ManagedRepositoryContent repository )
+ {
+ if ( repository == null )
+ {
+ throw new IllegalArgumentException( "Repository may not be null" );
+ }
+ ( (BaseContentItem) item ).repository = repository;
+ return this;
+ }
+
+ @Override
+ public N withAsset( StorageAsset asset )
+ {
+ if ( asset == null )
+ {
+ throw new IllegalArgumentException( "Asset may not be null" );
+ }
+ ( (BaseContentItem) item ).asset = asset;
+ return getNextBuilder( );
+ }
+
+ @Override
+ public O withAttribute( String key, String value )
+ {
+ if ( StringUtils.isEmpty( key ) )
+ {
+ throw new IllegalArgumentException( "Attribute key may not be null" );
+ }
+ item.putAttribute( key, value );
+ return getOptBuilder( );
+ }
+
+ protected void setRepository( ManagedRepositoryContent repository )
+ {
+ item.repository = repository;
+ }
+
+ @Override
+ public I build( )
+ {
+ return item;
+ }
+
+}
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/builder/ArchivaContentItemOptBuilder.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/builder/ArchivaContentItemOptBuilder.java
new file mode 100644
index 000000000..36ca84375
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/builder/ArchivaContentItemOptBuilder.java
@@ -0,0 +1,38 @@
+package org.apache.archiva.repository.content.base.builder;
+
+/*
+ * 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.Namespace;
+import org.apache.archiva.repository.content.Project;
+import org.apache.archiva.repository.content.Version;
+import org.apache.archiva.repository.content.base.ArchivaContentItem;
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public interface ArchivaContentItemOptBuilder extends OptBuilder<ArchivaContentItem, ArchivaContentItemOptBuilder>
+{
+ ArchivaContentItemOptBuilder withNamespace( Namespace namespace );
+
+ ArchivaContentItemOptBuilder withProject( Project project );
+
+ ArchivaContentItemOptBuilder withVersion( Version version );
+
+ ArchivaContentItem build();
+}
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/builder/DataItemOptBuilder.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/builder/DataItemOptBuilder.java
index 04da17d13..445946ec2 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/builder/DataItemOptBuilder.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/content/base/builder/DataItemOptBuilder.java
@@ -32,8 +32,6 @@ public interface DataItemOptBuilder
extends OptBuilder<ArchivaDataItem, DataItemOptBuilder>
{
- DataItemOptBuilder withParent( ContentItem parent );
-
DataItemOptBuilder withContentType( String contentType );
DataItemOptBuilder withDataType( DataItemType type );
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/mock/ManagedRepositoryContentMock.java b/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/mock/ManagedRepositoryContentMock.java
index dfd770380..2e7871d00 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/mock/ManagedRepositoryContentMock.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/test/java/org/apache/archiva/repository/mock/ManagedRepositoryContentMock.java
@@ -164,6 +164,12 @@ public class ManagedRepositoryContentMock implements ManagedRepositoryContent
}
@Override
+ public List<String> getArtifactVersions( ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
+ {
+ return null;
+ }
+
+ @Override
public List<? extends Artifact> getArtifacts( ContentItem item ) throws ContentAccessException
{
return null;
@@ -182,6 +188,24 @@ public class ManagedRepositoryContentMock implements ManagedRepositoryContent
}
@Override
+ public ContentItem getParent( ContentItem item )
+ {
+ return null;
+ }
+
+ @Override
+ public List<? extends ContentItem> getChildren( ContentItem item )
+ {
+ return null;
+ }
+
+ @Override
+ public <T extends ContentItem> T applyCharacteristic( Class<T> clazz, ContentItem item ) throws LayoutException
+ {
+ return null;
+ }
+
+ @Override
public void addArtifact( Path sourceFile, Artifact destination ) throws IllegalArgumentException
{