You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@archiva.apache.org by ma...@apache.org on 2019/08/25 11:15:30 UTC

[archiva] 02/02: Adding generic checksum storage for artifacts

This is an automated email from the ASF dual-hosted git repository.

martin_s pushed a commit to branch feature/storage_refactoring
in repository https://gitbox.apache.org/repos/asf/archiva.git

commit 232ac43077037ad349ae62e9c254dcc18378b1d3
Author: Martin Stockhammer <ma...@apache.org>
AuthorDate: Sun Aug 25 13:14:59 2019 +0200

    Adding generic checksum storage for artifacts
---
 .../repository/AbstractMetadataRepository.java     |  10 +-
 .../metadata/repository/MetadataRepository.java    |  62 +++++----
 .../repository/AbstractMetadataRepositoryTest.java |  15 +-
 .../cassandra/CassandraMetadataRepository.java     |  49 ++++++-
 .../repository/file/FileMetadataRepository.java    |   3 +-
 .../metadata/repository/jcr/JcrConstants.java      |   1 +
 .../repository/jcr/JcrMetadataRepository.java      | 155 +++++++++++++++++++--
 .../repository/jcr/OakRepositoryFactory.java       |   7 +-
 .../archiva/metadata/repository/jcr/jcr-schema.cnd |  29 ++--
 .../repository/jcr/JcrMetadataRepositoryTest.java  |   6 +-
 10 files changed, 267 insertions(+), 70 deletions(-)

diff --git a/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/AbstractMetadataRepository.java b/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/AbstractMetadataRepository.java
index bcb3e83..248e194 100644
--- a/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/AbstractMetadataRepository.java
+++ b/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/AbstractMetadataRepository.java
@@ -344,10 +344,6 @@ public abstract class AbstractMetadataRepository
         throw new UnsupportedOperationException();
     }
 
-    protected QueryParameter getParameterOrDefault(QueryParameter queryParameter) {
-        return queryParameter == null ? new QueryParameter( ) : queryParameter;
-    }
-
     @Override
     public <T extends MetadataFacet> Stream<T> getMetadataFacetStream( RepositorySession session, String repositoryId, Class<T> facetClazz ) throws MetadataRepositoryException
     {
@@ -409,13 +405,13 @@ public abstract class AbstractMetadataRepository
     @Override
     public List<ArtifactMetadata> getArtifactsByDateRange(RepositorySession session, String repoId, ZonedDateTime startTime, ZonedDateTime endTime)
             throws MetadataRepositoryException {
-        return getArtifactsByDateRange(session, repoId, startTime, endTime, getParameterOrDefault( null ));
+        return getArtifactsByDateRange(session, repoId, startTime, endTime, new QueryParameter(  ));
     }
 
     @Override
     public Stream<ArtifactMetadata> getArtifactStream( final RepositorySession session, final String repositoryId ) throws MetadataResolutionException
     {
-        return getArtifactStream( session, repositoryId, getParameterOrDefault( null ) );
+        return getArtifactStream( session, repositoryId, new QueryParameter(  ) );
     }
 
     @Override
@@ -423,7 +419,7 @@ public abstract class AbstractMetadataRepository
                                                        final String namespace, final String projectId,
                                                        final String projectVersion) throws MetadataResolutionException
     {
-        return getArtifactStream( session,repoId,namespace, projectId, projectVersion, getParameterOrDefault( null ));
+        return getArtifactStream( session,repoId,namespace, projectId, projectVersion, new QueryParameter(  ));
     }
 
     @Override
diff --git a/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/MetadataRepository.java b/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/MetadataRepository.java
index da54715..c267b36 100644
--- a/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/MetadataRepository.java
+++ b/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/MetadataRepository.java
@@ -107,7 +107,7 @@ public interface MetadataRepository
      * @param project      the project metadata to create or update
      * @throws MetadataRepositoryException if the update fails
      */
-    void updateProject( RepositorySession session, String repositoryId, ProjectMetadata project )
+    void updateProject( @Nonnull RepositorySession session, @Nonnull String repositoryId, @Nonnull ProjectMetadata project )
         throws MetadataRepositoryException;
 
     /**
@@ -121,8 +121,9 @@ public interface MetadataRepository
      * @param artifactMeta Information about the artifact itself.
      * @throws MetadataRepositoryException if something goes wrong during update.
      */
-    void updateArtifact( RepositorySession session, String repositoryId, String namespace, String projectId, String projectVersion,
-                         ArtifactMetadata artifactMeta )
+    void updateArtifact( @Nonnull RepositorySession session, @Nonnull String repositoryId,
+                         @Nonnull String namespace, @Nonnull String projectId, @Nonnull String projectVersion,
+                         @Nonnull ArtifactMetadata artifactMeta )
         throws MetadataRepositoryException;
 
     /**
@@ -136,8 +137,9 @@ public interface MetadataRepository
      * @param versionMetadata The metadata for the version
      * @throws MetadataRepositoryException if something goes wrong during update
      */
-    void updateProjectVersion( RepositorySession session, String repositoryId, String namespace, String projectId,
-                               ProjectVersionMetadata versionMetadata )
+    void updateProjectVersion( @Nonnull RepositorySession session, @Nonnull String repositoryId,
+                               @Nonnull String namespace, @Nonnull String projectId,
+                               @Nonnull ProjectVersionMetadata versionMetadata )
         throws MetadataRepositoryException;
 
     /**
@@ -149,7 +151,7 @@ public interface MetadataRepository
      * @param namespace The namespace ('.' separated)
      * @throws MetadataRepositoryException if something goes wrong during update
      */
-    void updateNamespace( RepositorySession session, String repositoryId, String namespace )
+    void updateNamespace( @Nonnull RepositorySession session, @Nonnull String repositoryId, @Nonnull String namespace )
         throws MetadataRepositoryException;
 
     /**
@@ -161,7 +163,7 @@ public interface MetadataRepository
      * @return The list of facet names, or an empty list, if there are no facets stored on this repository for the given facet id.
      * @throws MetadataRepositoryException if something goes wrong
      */
-    List<String> getMetadataFacets( RepositorySession session, String repositoryId, String facetId )
+    List<String> getMetadataFacets( @Nonnull RepositorySession session, @Nonnull String repositoryId, @Nonnull String facetId )
         throws MetadataRepositoryException;
 
 
@@ -182,7 +184,8 @@ public interface MetadataRepository
      * @throws MetadataRepositoryException
      * @since 3.0
      */
-    <T extends MetadataFacet> Stream<T> getMetadataFacetStream( RepositorySession session, String repositoryId, Class<T> facetClazz)
+    <T extends MetadataFacet> Stream<T> getMetadataFacetStream( @Nonnull RepositorySession session,
+                                                                @Nonnull String repositoryId, @Nonnull Class<T> facetClazz)
         throws MetadataRepositoryException;
 
     /**
@@ -198,7 +201,9 @@ public interface MetadataRepository
      * @throws MetadataRepositoryException
      * @since 3.0
      */
-    <T extends MetadataFacet> Stream<T> getMetadataFacetStream(RepositorySession session, String repositoryId, Class<T> facetClazz, QueryParameter queryParameter)
+    <T extends MetadataFacet> Stream<T> getMetadataFacetStream(@Nonnull RepositorySession session,
+                                                                @Nonnull String repositoryId,  @Nonnull Class<T> facetClazz,
+                                                                @Nonnull QueryParameter queryParameter)
         throws MetadataRepositoryException;
 
     /**
@@ -212,7 +217,7 @@ public interface MetadataRepository
      * @throws MetadataRepositoryException if something goes wrong
      * @since 1.4-M4
      */
-    boolean hasMetadataFacet( RepositorySession session, String repositoryId, String facetId )
+    boolean hasMetadataFacet( @Nonnull RepositorySession session, @Nonnull String repositoryId, @Nonnull String facetId )
         throws MetadataRepositoryException;
 
     /**
@@ -226,7 +231,8 @@ public interface MetadataRepository
      * @return The facet values
      * @throws MetadataRepositoryException if something goes wrong.
      */
-    MetadataFacet getMetadataFacet( RepositorySession session, String repositoryId, String facetId, String name )
+    MetadataFacet getMetadataFacet( @Nonnull RepositorySession session, @Nonnull String repositoryId, @Nonnull String facetId,
+                                    @Nonnull String name )
         throws MetadataRepositoryException;
 
     /**
@@ -243,7 +249,8 @@ public interface MetadataRepository
      * @throws MetadataRepositoryException if the data cannot be retrieved from the backend
      * @since 3.0
      */
-    <T extends MetadataFacet> T getMetadataFacet(RepositorySession session, String repositoryId, Class<T> clazz, String name)
+    <T extends MetadataFacet> T getMetadataFacet(@Nonnull RepositorySession session, @Nonnull String repositoryId,
+                                                 @Nonnull Class<T> clazz, @Nonnull String name)
     throws MetadataRepositoryException;
 
     /**
@@ -254,7 +261,8 @@ public interface MetadataRepository
      * @param metadataFacet The facet to add
      * @throws MetadataRepositoryException if the facet cannot be stored.
      */
-    void addMetadataFacet( RepositorySession session, String repositoryId, MetadataFacet metadataFacet )
+    void addMetadataFacet( @Nonnull RepositorySession session, @Nonnull String repositoryId,
+                           @Nonnull MetadataFacet metadataFacet )
         throws MetadataRepositoryException;
 
     /**
@@ -265,7 +273,7 @@ public interface MetadataRepository
      * @param facetId The facet id
      * @throws MetadataRepositoryException if the removal fails
      */
-    void removeMetadataFacets( RepositorySession session, String repositoryId, String facetId )
+    void removeMetadataFacets( @Nonnull RepositorySession session, @Nonnull String repositoryId, @Nonnull String facetId )
         throws MetadataRepositoryException;
 
     /**
@@ -276,7 +284,7 @@ public interface MetadataRepository
      * @param facetId The facet id
      * @param name The facet name or path
      */
-    void removeMetadataFacet( RepositorySession session, String repositoryId, String facetId, String name )
+    void removeMetadataFacet( @Nonnull RepositorySession session, @Nonnull String repositoryId, @Nonnull String facetId, @Nonnull String name )
         throws MetadataRepositoryException;
 
 
@@ -285,7 +293,8 @@ public interface MetadataRepository
      * uses default query parameters.
      *
      */
-    List<ArtifactMetadata> getArtifactsByDateRange(RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime )
+    List<ArtifactMetadata> getArtifactsByDateRange( @Nonnull RepositorySession session, @Nonnull String repositoryId,
+                                                    @Nullable ZonedDateTime startTime, @Nullable ZonedDateTime endTime )
         throws MetadataRepositoryException;
 
     /**
@@ -303,7 +312,9 @@ public interface MetadataRepository
      * @throws MetadataRepositoryException if the query fails.
      * @since 3.0
      */
-    List<ArtifactMetadata> getArtifactsByDateRange(RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime, QueryParameter queryParameter )
+    List<ArtifactMetadata> getArtifactsByDateRange(@Nonnull RepositorySession session, @Nonnull String repositoryId,
+                                                   @Nullable ZonedDateTime startTime, @Nullable ZonedDateTime endTime,
+                                                   @Nonnull QueryParameter queryParameter )
             throws MetadataRepositoryException;
 
 
@@ -320,7 +331,8 @@ public interface MetadataRepository
      * @throws MetadataRepositoryException
      * @since 3.0
      */
-    Stream<ArtifactMetadata> getArtifactByDateRangeStream( RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime )
+    Stream<ArtifactMetadata> getArtifactByDateRangeStream( @Nonnull RepositorySession session, @Nonnull String repositoryId,
+                                                           @Nullable ZonedDateTime startTime, @Nullable ZonedDateTime endTime )
         throws MetadataRepositoryException;
 
     /**
@@ -337,8 +349,9 @@ public interface MetadataRepository
      * @throws MetadataRepositoryException
      * @since 3.0
      */
-    Stream<ArtifactMetadata> getArtifactByDateRangeStream( RepositorySession session, String repositoryId,
-                                                           ZonedDateTime startTime, ZonedDateTime endTime, QueryParameter queryParameter)
+    Stream<ArtifactMetadata> getArtifactByDateRangeStream( @Nonnull RepositorySession session, @Nonnull String repositoryId,
+                                                           @Nullable ZonedDateTime startTime, @Nullable ZonedDateTime endTime,
+                                                           @Nonnull QueryParameter queryParameter)
         throws MetadataRepositoryException;
 
 
@@ -351,7 +364,7 @@ public interface MetadataRepository
      * @return The list of artifacts that match the given checksum.
      * @throws MetadataRepositoryException
      */
-    List<ArtifactMetadata> getArtifactsByChecksum(RepositorySession session, String repositoryId, String checksum )
+    List<ArtifactMetadata> getArtifactsByChecksum(@Nonnull RepositorySession session, @Nonnull String repositoryId, @Nonnull String checksum )
         throws MetadataRepositoryException;
 
     /**
@@ -365,7 +378,8 @@ public interface MetadataRepository
      * @return a list of artifacts
      * @throws MetadataRepositoryException
      */
-    List<ArtifactMetadata> getArtifactsByProjectVersionMetadata( RepositorySession session, String key, String value, String repositoryId )
+    List<ArtifactMetadata> getArtifactsByProjectVersionMetadata( @Nonnull RepositorySession session, @Nonnull String key, @Nonnull String value,
+                                                                 @Nullable String repositoryId )
         throws MetadataRepositoryException;
 
     /**
@@ -467,7 +481,7 @@ public interface MetadataRepository
      * @return A stream of artifact metadata objects for each artifact found in the repository.
      * @since 3.0
      */
-    Stream<ArtifactMetadata> getArtifactStream( @Nonnull RepositorySession session, @Nonnull String repositoryId, @Nullable QueryParameter queryParameter )
+    Stream<ArtifactMetadata> getArtifactStream( @Nonnull RepositorySession session, @Nonnull String repositoryId, @Nonnull QueryParameter queryParameter )
         throws MetadataResolutionException;
 
     /**
@@ -500,7 +514,7 @@ public interface MetadataRepository
      */
     Stream<ArtifactMetadata> getArtifactStream( @Nonnull RepositorySession session, @Nonnull String repoId,
                                                 @Nonnull String namespace, @Nonnull String projectId,
-                                                @Nonnull String projectVersion, @Nullable QueryParameter queryParameter )
+                                                @Nonnull String projectVersion, @Nonnull QueryParameter queryParameter )
         throws MetadataResolutionException;
 
     /**
diff --git a/archiva-modules/metadata/metadata-repository-api/src/test/java/org/apache/archiva/metadata/repository/AbstractMetadataRepositoryTest.java b/archiva-modules/metadata/metadata-repository-api/src/test/java/org/apache/archiva/metadata/repository/AbstractMetadataRepositoryTest.java
index 6fb1e75..e24f456 100644
--- a/archiva-modules/metadata/metadata-repository-api/src/test/java/org/apache/archiva/metadata/repository/AbstractMetadataRepositoryTest.java
+++ b/archiva-modules/metadata/metadata-repository-api/src/test/java/org/apache/archiva/metadata/repository/AbstractMetadataRepositoryTest.java
@@ -1207,19 +1207,22 @@ public abstract class AbstractMetadataRepositoryTest
     public void testGetArtifactStream( )
         throws Exception
     {
+        ArtifactMetadata artifact1 = createArtifact( );
+        ArtifactMetadata artifact2 = createArtifact( "pom" );
         try ( RepositorySession session = getSessionFactory( ).createSession( ) )
         {
-            ArtifactMetadata artifact1 = createArtifact( );
-            ArtifactMetadata artifact2 = createArtifact( "pom" );
+
             getRepository( ).updateArtifact( session, TEST_REPO_ID, TEST_NAMESPACE, TEST_PROJECT, TEST_PROJECT_VERSION, artifact1 );
             getRepository( ).updateArtifact( session, TEST_REPO_ID, TEST_NAMESPACE, TEST_PROJECT, TEST_PROJECT_VERSION, artifact2 );
-
+        }
+        try ( RepositorySession session = getSessionFactory( ).createSession( ) ) {
             tryAssert( ( ) -> {
                 Stream<ArtifactMetadata> artifacts =
                     getRepository( ).getArtifactStream( session, TEST_REPO_ID, TEST_NAMESPACE, TEST_PROJECT, TEST_PROJECT_VERSION );
                 assertNotNull( artifacts );
                 List<ArtifactMetadata> actual = artifacts
                     .sorted( ( o1, o2 ) -> o1.getId( ).compareTo( o2.getId( ) ) ).collect( Collectors.toList( ) );
+                assertEquals( 2, actual.size( ) );
                 assertEquals( Arrays.asList( artifact1, artifact2 ), actual );
             } );
 
@@ -1628,8 +1631,10 @@ public abstract class AbstractMetadataRepositoryTest
             getRepository( ).updateArtifact( session, TEST_REPO_ID, TEST_NAMESPACE, TEST_PROJECT, TEST_PROJECT_VERSION, artifact );
             session.save( );
 
-            assertEquals( Collections.singletonList( artifact ),
-                new ArrayList<>( getRepository( ).getArtifactsByChecksum( session, TEST_REPO_ID, TEST_SHA256 ) ) );
+            tryAssert( () ->
+                assertEquals( Collections.singletonList( artifact ),
+                new ArrayList<>( getRepository( ).getArtifactsByChecksum( session, TEST_REPO_ID, TEST_SHA256 ) ))
+            );
 
         }
     }
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraMetadataRepository.java b/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraMetadataRepository.java
index 844bba7..7637135 100644
--- a/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraMetadataRepository.java
+++ b/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraMetadataRepository.java
@@ -2095,7 +2095,7 @@ public class CassandraMetadataRepository
             }
         }
 
-        return mapArtifactMetadataToArtifact( metadataFacetResult, artifactMetadatas );
+        return mapArtifactFacetToArtifact( metadataFacetResult, artifactMetadatas );
     }
 
     @Override
@@ -2354,13 +2354,13 @@ public class CassandraMetadataRepository
             .addEqualsExpression( PROJECT_VERSION.toString(), projectVersion ) //
             .execute();
 
-        return mapArtifactMetadataToArtifact(result, artifactMetadatas);
+        return mapArtifactFacetToArtifact(result, artifactMetadatas);
     }
 
     /**
      * Attach metadata to each of the  ArtifactMetadata objects
      */
-    private List<ArtifactMetadata> mapArtifactMetadataToArtifact(QueryResult<OrderedRows<String, String, String>> result, List<ArtifactMetadata> artifactMetadatas) {
+    private List<ArtifactMetadata> mapArtifactFacetToArtifact( QueryResult<OrderedRows<String, String, String>> result, List<ArtifactMetadata> artifactMetadatas) {
         if ( result.get() == null || result.get().getCount() < 1 )
         {
             return artifactMetadatas;
@@ -2475,7 +2475,8 @@ public class CassandraMetadataRepository
      * any property.
      */
     @Override
-    public List<ArtifactMetadata> searchArtifacts( RepositorySession session, String repositoryId, String text, boolean exact )
+    public List<ArtifactMetadata> searchArtifacts( final RepositorySession session, final String repositoryId,
+                                                   final String text, final boolean exact )
         throws MetadataRepositoryException
     {
         return getArtifactsByMetadata( session, null, text, repositoryId );
@@ -2485,7 +2486,8 @@ public class CassandraMetadataRepository
      * The exact parameter is ignored as we can't do non exact searches in Cassandra
      */
     @Override
-    public List<ArtifactMetadata> searchArtifacts( RepositorySession session, String repositoryId, String key, String text, boolean exact )
+    public List<ArtifactMetadata> searchArtifacts( final RepositorySession session, final String repositoryId,
+                                                   final String key, final String text, final boolean exact )
         throws MetadataRepositoryException
     {
         // TODO optimize
@@ -2494,4 +2496,41 @@ public class CassandraMetadataRepository
         artifacts.addAll( getArtifactsByProperty( session, key, text, repositoryId ) );
         return artifacts;
     }
+
+    @Override
+    public Stream<ArtifactMetadata> getArtifactStream( final RepositorySession session, final String repositoryId,
+                                                       final QueryParameter queryParameter ) throws MetadataResolutionException
+    {
+        RangeSlicesQuery<String, String, String> query = HFactory //
+            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
+            .setColumnFamily( cassandraArchivaManager.getArtifactMetadataFamilyName( ) ) //
+            .setColumnNames( ArtifactMetadataModel.COLUMNS ); //
+
+        query = query.addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId );
+
+        QueryResult<OrderedRows<String, String, String>> result = query.execute();
+
+        try
+        {
+            return StreamSupport.stream( createResultSpliterator( result, ( Row<String, String, String> row, ArtifactMetadata last ) ->
+                mapArtifactMetadataStringColumnSlice( row.getKey( ), row.getColumnSlice( ) ) ), false )
+                .skip( queryParameter.getOffset( ) ).limit( queryParameter.getLimit( ) );
+        }
+        catch ( MetadataRepositoryException e )
+        {
+            throw new MetadataResolutionException( e.getMessage( ), e );
+        }
+    }
+
+    @Override
+    public Stream<ArtifactMetadata> getArtifactStream( final RepositorySession session, final String repoId,
+                                                       final String namespace, final String projectId, final String projectVersion,
+                                                       final QueryParameter queryParameter ) throws MetadataResolutionException
+    {
+        // Currently we have to align the facets with the artifacts, which means querying artifacts, querying facets and combining them.
+        // I so no stream friendly way to do this, so we just use the collection based method and return the stream.
+        // TODO: Maybe we can query the facets for each artifact separately, but not sure, if this affects performance significantly
+        //       We need some data to verify this.
+        return getArtifacts( session, repoId, namespace, projectId, projectVersion ).stream( ).skip( queryParameter.getOffset( ) ).limit( queryParameter.getLimit( ) );
+    }
 }
diff --git a/archiva-modules/plugins/metadata-store-file/src/main/java/org/apache/archiva/metadata/repository/file/FileMetadataRepository.java b/archiva-modules/plugins/metadata-store-file/src/main/java/org/apache/archiva/metadata/repository/file/FileMetadataRepository.java
index 4191945..4719d92 100644
--- a/archiva-modules/plugins/metadata-store-file/src/main/java/org/apache/archiva/metadata/repository/file/FileMetadataRepository.java
+++ b/archiva-modules/plugins/metadata-store-file/src/main/java/org/apache/archiva/metadata/repository/file/FileMetadataRepository.java
@@ -1214,10 +1214,9 @@ public class FileMetadataRepository
 
     @Override
     public Stream<ArtifactMetadata> getArtifactStream( @Nonnull final RepositorySession session, @Nonnull final String repositoryId,
-                                                       @Nullable QueryParameter queryParameter ) throws MetadataResolutionException
+                                                       @Nonnull QueryParameter queryParameter ) throws MetadataResolutionException
     {
 
-        queryParameter = getParameterOrDefault( queryParameter );
         return getAllNamespacesStream( session, repositoryId ).filter( Objects::nonNull ).flatMap( ns ->
             {
                 try
diff --git a/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/JcrConstants.java b/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/JcrConstants.java
index 46caef9..d0119c7 100644
--- a/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/JcrConstants.java
+++ b/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/JcrConstants.java
@@ -45,6 +45,7 @@ public interface JcrConstants
     String MIXIN_META_LICENSE = "archiva:meta_license";
     String MIXIN_META_MAILINGLIST = "archiva:meta_mailinglist";
     String DEPENDENCY_NODE_TYPE = "archiva:dependency";
+    String CHECKSUM_NODE_TYPE = "archiva:checksum";
 
     // Must be alphabetically ordered!
     String[] PROJECT_VERSION_VERSION_PROPERTIES = {"ci.system","ci.url", "description", "incomplete", "issue.system","issue.url", "name", "org.name", "org.url", "url", "scm.connection", "scm.developerConnection", "scm.url"};
diff --git a/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/JcrMetadataRepository.java b/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/JcrMetadataRepository.java
index 25b11de..a9d0a85 100644
--- a/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/JcrMetadataRepository.java
+++ b/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/JcrMetadataRepository.java
@@ -20,6 +20,7 @@ package org.apache.archiva.metadata.repository.jcr;
  */
 
 import com.google.common.collect.ImmutableMap;
+import org.apache.archiva.checksum.ChecksumAlgorithm;
 import org.apache.archiva.metadata.QueryParameter;
 import org.apache.archiva.metadata.model.*;
 import org.apache.archiva.metadata.model.maven2.MavenArtifactFacet;
@@ -42,6 +43,7 @@ import org.slf4j.LoggerFactory;
 
 import javax.jcr.NamespaceRegistry;
 import javax.jcr.Node;
+import javax.jcr.NodeIterator;
 import javax.jcr.PathNotFoundException;
 import javax.jcr.Property;
 import javax.jcr.Repository;
@@ -196,8 +198,22 @@ public class JcrMetadataRepository
             node.setProperty( "whenGathered", cal );
 
             node.setProperty( "size", artifactMeta.getSize() );
-            node.setProperty( "md5", artifactMeta.getMd5() );
-            node.setProperty( "sha1", artifactMeta.getSha1() );
+
+            int idx=0;
+            Node cslistNode = getOrAddNodeByPath( node, "checksums" );
+            NodeIterator nit = cslistNode.getNodes("*");
+            while (nit.hasNext()) {
+                Node csNode = nit.nextNode();
+                if (csNode.isNodeType( CHECKSUM_NODE_TYPE )) {
+                    csNode.remove();
+                }
+            }
+            for ( Map.Entry<ChecksumAlgorithm, String> entry : artifactMeta.getChecksums().entrySet()) {
+                String type = entry.getKey( ).name( );
+                Node csNode = cslistNode.addNode( type , CHECKSUM_NODE_TYPE);
+                csNode.setProperty( "type", type );
+                csNode.setProperty( "value", entry.getValue( ) );
+            }
 
             node.setProperty( "version", artifactMeta.getVersion() );
 
@@ -836,7 +852,7 @@ public class JcrMetadataRepository
         final Session jcrSession = getSession( session );
         List<ArtifactMetadata> artifacts;
 
-        String q = getArtifactQuery( repositoryId ) + " AND ([sha1] = $checksum OR [md5] = $checksum)";
+        String q = getArtifactQuery( repositoryId ).append(" AND ([artifact].[checksums/*/value] = $checksum)").toString();
 
         try
         {
@@ -1688,20 +1704,33 @@ public class JcrMetadataRepository
             artifact.setSize( artifactNode.getProperty( "size" ).getLong() );
         }
 
-        if ( artifactNode.hasProperty( "md5" ) )
-        {
-            artifact.setMd5( artifactNode.getProperty( "md5" ).getString() );
-        }
-
-        if ( artifactNode.hasProperty( "sha1" ) )
-        {
-            artifact.setSha1( artifactNode.getProperty( "sha1" ).getString() );
+        Node cslistNode = getOrAddNodeByPath( artifactNode, "checksums" );
+        NodeIterator csNodeIt = cslistNode.getNodes( "*" );
+        while (csNodeIt.hasNext()) {
+            Node csNode = csNodeIt.nextNode( );
+            if (csNode.isNodeType( CHECKSUM_NODE_TYPE ))
+            {
+                addChecksum( artifact, csNode );
+            }
         }
 
         retrieveFacetProperties( artifact, artifactNode );
         return artifact;
     }
 
+    private void addChecksum(ArtifactMetadata artifact, Node n) {
+        try
+        {
+            ChecksumAlgorithm alg = ChecksumAlgorithm.valueOf( n.getProperty( "type" ).getString() );
+            String value = n.getProperty( "value" ).getString( );
+            artifact.setChecksum( alg, value );
+        }
+        catch ( Throwable e )
+        {
+            log.error( "Could not set checksum from node {}", n );
+        }
+    }
+
     private static String getPropertyString( Node node, String name )
         throws RepositoryException
     {
@@ -1996,4 +2025,108 @@ public class JcrMetadataRepository
     {
         return repository.login(new SimpleCredentials( "admin", "admin".toCharArray() ) );
     }
+
+    private static boolean isArtifactNodeType(Node n) {
+        try
+        {
+            return n != null && n.isNodeType( ARTIFACT_NODE_TYPE );
+        }
+        catch ( RepositoryException e )
+        {
+            return false;
+        }
+    }
+
+    private Optional<ArtifactMetadata> getArtifactOptional(final String repositoryId, final Node n) {
+        try
+        {
+            return Optional.ofNullable( getArtifactFromNode( repositoryId, n ) );
+        }
+        catch ( RepositoryException e )
+        {
+            return Optional.empty( );
+        }
+    }
+
+    private Optional<ArtifactMetadata> getArtifactOptional(final String repositoryId, final Row row) {
+        try
+        {
+            return Optional.ofNullable( getArtifactFromNode( repositoryId, row.getNode( "artifact" ) ) );
+        }
+        catch ( RepositoryException e )
+        {
+            return Optional.empty( );
+        }
+    }
+
+    @Override
+    public Stream<ArtifactMetadata> getArtifactStream( final RepositorySession session, final String repositoryId,
+                                                       final String namespace, final String projectId, final String projectVersion,
+                                                       final QueryParameter queryParameter ) throws MetadataResolutionException
+    {
+        final Session jcrSession;
+        try
+        {
+            jcrSession = getSession( session );
+        }
+        catch ( MetadataRepositoryException e )
+        {
+            throw new MetadataResolutionException( e.getMessage( ) );
+        }
+
+        try
+        {
+            Node root = jcrSession.getRootNode();
+            String path = getProjectVersionPath( repositoryId, namespace, projectId, projectVersion );
+
+            if ( root.hasNode( path ) )
+            {
+                Node node = root.getNode( path );
+                return StreamSupport.stream( JcrUtils.getChildNodes( node ).spliterator( ), false ).filter(JcrMetadataRepository::isArtifactNodeType)
+                    .map( n -> getArtifactOptional( repositoryId, n ) )
+                .map( Optional::get ).skip( queryParameter.getOffset( ) ).limit( queryParameter.getLimit( ) );
+            } else {
+                return Stream.empty( );
+            }
+        }
+        catch ( RepositoryException e )
+        {
+            throw new MetadataResolutionException( e.getMessage(), e );
+        }
+    }
+
+    @Override
+    public Stream<ArtifactMetadata> getArtifactStream( final RepositorySession session, final String repositoryId,
+                                                       final QueryParameter queryParameter ) throws MetadataResolutionException
+    {
+        final Session jcrSession;
+        try
+        {
+            jcrSession = getSession( session );
+        }
+        catch ( MetadataRepositoryException e )
+        {
+            throw new MetadataResolutionException( e.getMessage( ), e );
+        }
+        List<ArtifactMetadata> artifacts;
+
+        String q = getArtifactQuery( repositoryId ).toString();
+
+        try
+        {
+            Query query = jcrSession.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
+            QueryResult result = query.execute();
+
+            return StreamSupport.stream( createResultSpliterator( result, ( Row row ) ->
+            getArtifactOptional( repositoryId, row ) ), false )
+                .map(Optional::get)
+                .skip( queryParameter.getOffset( ) ).limit( queryParameter.getLimit( ) );
+
+        }
+        catch ( RepositoryException | MetadataRepositoryException e )
+        {
+            throw new MetadataResolutionException( e.getMessage(), e );
+        }
+
+    }
 }
diff --git a/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/OakRepositoryFactory.java b/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/OakRepositoryFactory.java
index 56f17b4..d303048 100644
--- a/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/OakRepositoryFactory.java
+++ b/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/OakRepositoryFactory.java
@@ -485,7 +485,12 @@ public class OakRepositoryFactory
                     initBaseRule(idxBuilder.indexRule( ARTIFACT_NODE_TYPE ))
                         .property( "whenGathered" ).type("Date").propertyIndex().analyzed().ordered()
                         .property("size").type("Long").propertyIndex().analyzed().ordered()
-                        .property("version").propertyIndex().analyzed().ordered();
+                        .property("version").propertyIndex().analyzed().ordered()
+                        .property("checksums/*/value").propertyIndex();
+
+                    initBaseRule( idxBuilder.indexRule( CHECKSUM_NODE_TYPE ) )
+                        .property("type").propertyIndex()
+                        .property("value").propertyIndex();
 
                     initRegexAll( idxBuilder.indexRule( FACET_NODE_TYPE ) )
                         .property("archiva:facetId").propertyIndex().analyzed().ordered()
diff --git a/archiva-modules/plugins/metadata-store-jcr/src/main/resources/org/apache/archiva/metadata/repository/jcr/jcr-schema.cnd b/archiva-modules/plugins/metadata-store-jcr/src/main/resources/org/apache/archiva/metadata/repository/jcr/jcr-schema.cnd
index ce33089..7fdb678 100644
--- a/archiva-modules/plugins/metadata-store-jcr/src/main/resources/org/apache/archiva/metadata/repository/jcr/jcr-schema.cnd
+++ b/archiva-modules/plugins/metadata-store-jcr/src/main/resources/org/apache/archiva/metadata/repository/jcr/jcr-schema.cnd
@@ -26,16 +26,16 @@
  + content (archiva:content) primary
 
 [archiva:content] > archiva:base mixin
- + * (archiva:namespace) multiple
+ + * (archiva:namespace)
 
 [archiva:namespace] > archiva:base mixin
  - namespace (string)
- + * (archiva:namespace) multiple
- + * (archiva:project) multiple
+ + * (archiva:namespace)
+ + * (archiva:project)
 
 [archiva:project] > archiva:base mixin
  - name (string)
- + * (archiva:projectVersion) multiple
+ + * (archiva:projectVersion)
 
 [archiva:meta_scm] mixin
   - scm.connection (string)
@@ -79,7 +79,10 @@
  - optional (boolean)
 
 [archiva:dependencies] mixin
- + * (archiva:dependency) multiple
+ + * (archiva:dependency)
+
+[archiva:checksums]
+ + * (archiva:checksum)
 
 [archiva:checksum]
  - type (string)
@@ -90,20 +93,18 @@
  - description (string)
  - url (uri)
  - incomplete (boolean)
- + * (archiva:artifact) multiple
- + license (archiva:meta_license) multiple
- + mailinglist (archiva:meta_mailinglist) multiple
- + dependencies (archiva:dependencies)
- + * (archiva:facet) multiple
+ + * (archiva:artifact)
+ + * (archiva:meta_license)
+ + * (archiva:meta_mailinglist)
+ + * (archiva:dependencies)
+ + * (archiva:facet)
 
 [archiva:artifact] > archiva:base mixin
  - whenGathered (date)
  - size (long)
- - md5 (string)
- - sha1 (string)
  - version (string)
- + checksum (archiva:checksum) multiple
- + * (archiva:facet) multiple
+ + * (archiva:checksum)
+ + * (archiva:facet)
 
 [archiva:facet] > archiva:base mixin
  - archiva:facetId
diff --git a/archiva-modules/plugins/metadata-store-jcr/src/test/java/org/apache/archiva/metadata/repository/jcr/JcrMetadataRepositoryTest.java b/archiva-modules/plugins/metadata-store-jcr/src/test/java/org/apache/archiva/metadata/repository/jcr/JcrMetadataRepositoryTest.java
index 58bb441..9f7bd8c 100644
--- a/archiva-modules/plugins/metadata-store-jcr/src/test/java/org/apache/archiva/metadata/repository/jcr/JcrMetadataRepositoryTest.java
+++ b/archiva-modules/plugins/metadata-store-jcr/src/test/java/org/apache/archiva/metadata/repository/jcr/JcrMetadataRepositoryTest.java
@@ -90,8 +90,12 @@ public class JcrMetadataRepositoryTest
     }
 
     @Before
-    public void setup() throws MetadataRepositoryException, RepositoryException, MetadataSessionException
+    @Override
+    public void setUp() throws Exception
     {
+        super.setUp();
+        super.assertMaxTries=5;
+        super.assertRetrySleepMs = 500;
         try( JcrRepositorySession session = (JcrRepositorySession) getSessionFactory().createSession() ) {
             Session jcrSession = session.getJcrSession( );
             if (jcrSession.itemExists( "/repositories/test" ))