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/19 22:08:15 UTC

[archiva] branch feature/storage_refactoring updated (118604a -> d4ce388)

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

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


    from 118604a  Fixing unit tests
     new 6cf4073  Changing facet factories. Adding stream methods to metadata repository.
     new d4ce388  Implementing new stream methods

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../storage/maven2/MavenArtifactFacetFactory.java  |  12 +-
 .../storage/maven2/MavenProjectFacetFactory.java   |  12 +-
 .../NewArtifactsRssFeedProcessorTest.java          |   7 +-
 .../archiva/metadata/model/ArtifactMetadata.java   |   1 +
 .../metadata/model/MetadataFacetFactory.java       |  14 +-
 .../model/facets/AbstractMetadataFacetFactory.java |  67 +++++
 .../repository/AbstractMetadataRepository.java     |  77 +++++-
 .../metadata/repository/MetadataRepository.java    | 159 +++++++++++-
 .../metadata/repository/MetadataResolver.java      |   8 +
 .../metadata/repository/MetadataService.java       | 100 ++++++++
 .../repository/AbstractMetadataRepositoryTest.java | 127 ++++++++--
 .../apache/archiva/audit/AuditEventFactory.java    |  24 +-
 .../generic/GenericMetadataFacetFactory.java       |  13 +-
 .../cassandra/CassandraMetadataRepository.java     | 106 +++++++-
 .../CassandraRepositorySessionFactory.java         |  18 +-
 .../cassandra/CassandraMetadataRepositoryTest.java |   8 +-
 .../repository/file/FileMetadataRepository.java    |  85 +++++--
 .../file/FileRepositorySessionFactory.java         |  18 +-
 .../file/FileMetadataRepositoryTest.java           |   8 +-
 .../repository/jcr/JcrMetadataRepository.java      | 274 ++++++++++++++-------
 .../jcr/JcrRepositorySessionFactory.java           |  52 ++--
 .../repository/jcr/OakRepositoryFactory.java       |  87 ++-----
 .../archiva/metadata/repository/jcr/jcr-schema.cnd |   4 +-
 .../repository/jcr/JcrMetadataRepositoryTest.java  |  15 +-
 .../JcrRepositoryStatisticsGatheringTest.java      |   8 +-
 .../reports/RepositoryProblemFacetFactory.java     |  14 +-
 .../stats/RepositoryStatisticsFactory.java         |  15 +-
 27 files changed, 1006 insertions(+), 327 deletions(-)
 create mode 100644 archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/facets/AbstractMetadataFacetFactory.java
 create mode 100644 archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/MetadataService.java


[archiva] 01/02: Changing facet factories. Adding stream methods to metadata repository.

Posted by ma...@apache.org.
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 6cf4073a9e73b6517c51dc22db75fd97d2523695
Author: Martin Stockhammer <ma...@apache.org>
AuthorDate: Sun Aug 18 20:56:46 2019 +0200

    Changing facet factories. Adding stream methods to metadata repository.
---
 .../storage/maven2/MavenArtifactFacetFactory.java  |  12 +-
 .../storage/maven2/MavenProjectFacetFactory.java   |  12 +-
 .../metadata/model/MetadataFacetFactory.java       |  14 +-
 .../model/facets/AbstractMetadataFacetFactory.java |  67 ++++++
 .../metadata/repository/MetadataRepository.java    | 159 ++++++++++++-
 .../metadata/repository/MetadataResolver.java      |   8 +
 .../metadata/repository/MetadataService.java       | 100 ++++++++
 .../repository/AbstractMetadataRepositoryTest.java |  68 ++++--
 .../apache/archiva/audit/AuditEventFactory.java    |  24 +-
 .../generic/GenericMetadataFacetFactory.java       |  13 +-
 .../repository/jcr/JcrMetadataRepository.java      | 265 ++++++++++++++-------
 .../jcr/JcrRepositorySessionFactory.java           |  52 ++--
 .../repository/jcr/OakRepositoryFactory.java       |   4 +-
 .../archiva/metadata/repository/jcr/jcr-schema.cnd |   3 +-
 .../repository/jcr/JcrMetadataRepositoryTest.java  |  15 +-
 .../JcrRepositoryStatisticsGatheringTest.java      |   8 +-
 .../reports/RepositoryProblemFacetFactory.java     |  14 +-
 .../stats/RepositoryStatisticsFactory.java         |  15 +-
 18 files changed, 662 insertions(+), 191 deletions(-)

diff --git a/archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/metadata/repository/storage/maven2/MavenArtifactFacetFactory.java b/archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/metadata/repository/storage/maven2/MavenArtifactFacetFactory.java
index e0c57ba..29bd3f6 100644
--- a/archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/metadata/repository/storage/maven2/MavenArtifactFacetFactory.java
+++ b/archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/metadata/repository/storage/maven2/MavenArtifactFacetFactory.java
@@ -19,8 +19,8 @@ package org.apache.archiva.metadata.repository.storage.maven2;
  * under the License.
  */
 
-import org.apache.archiva.metadata.model.MetadataFacet;
 import org.apache.archiva.metadata.model.MetadataFacetFactory;
+import org.apache.archiva.metadata.model.facets.AbstractMetadataFacetFactory;
 import org.apache.archiva.metadata.model.maven2.MavenArtifactFacet;
 import org.springframework.stereotype.Service;
 
@@ -29,16 +29,20 @@ import org.springframework.stereotype.Service;
  */
 @Service("metadataFacetFactory#org.apache.archiva.metadata.repository.storage.maven2.artifact")
 public class MavenArtifactFacetFactory
-    implements MetadataFacetFactory
+    extends AbstractMetadataFacetFactory<MavenArtifactFacet>
 {
+    public MavenArtifactFacetFactory() {
+        super( MavenArtifactFacet.class);
+    }
+
     @Override
-    public MetadataFacet createMetadataFacet()
+    public MavenArtifactFacet createMetadataFacet()
     {
         return new MavenArtifactFacet();
     }
 
     @Override
-    public MetadataFacet createMetadataFacet( String repositoryId, String name )
+    public MavenArtifactFacet createMetadataFacet( String repositoryId, String name )
     {
         throw new UnsupportedOperationException( "There is no valid name for artifact facets" );
     }
diff --git a/archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/metadata/repository/storage/maven2/MavenProjectFacetFactory.java b/archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/metadata/repository/storage/maven2/MavenProjectFacetFactory.java
index a7bd89a..a3b68c6 100644
--- a/archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/metadata/repository/storage/maven2/MavenProjectFacetFactory.java
+++ b/archiva-modules/archiva-maven/archiva-maven-repository/src/main/java/org/apache/archiva/metadata/repository/storage/maven2/MavenProjectFacetFactory.java
@@ -19,8 +19,8 @@ package org.apache.archiva.metadata.repository.storage.maven2;
  * under the License.
  */
 
-import org.apache.archiva.metadata.model.MetadataFacet;
 import org.apache.archiva.metadata.model.MetadataFacetFactory;
+import org.apache.archiva.metadata.model.facets.AbstractMetadataFacetFactory;
 import org.springframework.stereotype.Service;
 
 /**
@@ -28,16 +28,20 @@ import org.springframework.stereotype.Service;
  */
 @Service( "metadataFacetFactory#org.apache.archiva.metadata.repository.storage.maven2.project" )
 public class MavenProjectFacetFactory
-    implements MetadataFacetFactory
+    extends AbstractMetadataFacetFactory<MavenProjectFacet>
 {
+    public MavenProjectFacetFactory() {
+        super( MavenProjectFacet.class );
+    }
+
     @Override
-    public MetadataFacet createMetadataFacet()
+    public MavenProjectFacet createMetadataFacet()
     {
         return new MavenProjectFacet();
     }
 
     @Override
-    public MetadataFacet createMetadataFacet( String repositoryId, String name )
+    public MavenProjectFacet createMetadataFacet( String repositoryId, String name )
     {
         throw new UnsupportedOperationException( "There is no valid name for project version facets" );
     }
diff --git a/archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/MetadataFacetFactory.java b/archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/MetadataFacetFactory.java
index e0804ed..ec35ad7 100644
--- a/archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/MetadataFacetFactory.java
+++ b/archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/MetadataFacetFactory.java
@@ -19,9 +19,17 @@ package org.apache.archiva.metadata.model;
  * under the License.
  */
 
-public interface MetadataFacetFactory
+public interface MetadataFacetFactory<T extends MetadataFacet>
 {
-    MetadataFacet createMetadataFacet();
+    T createMetadataFacet();
 
-    MetadataFacet createMetadataFacet( String repositoryId, String name );
+    T createMetadataFacet( String repositoryId, String name );
+
+    default boolean assignsFacet( Class<?> clazz ) {
+        return getFacetClass( ).isAssignableFrom( clazz );
+    }
+
+    Class<T> getFacetClass( );
+
+    String getFacetId();
 }
diff --git a/archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/facets/AbstractMetadataFacetFactory.java b/archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/facets/AbstractMetadataFacetFactory.java
new file mode 100644
index 0000000..725774e
--- /dev/null
+++ b/archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/facets/AbstractMetadataFacetFactory.java
@@ -0,0 +1,67 @@
+package org.apache.archiva.metadata.model.facets;
+
+/*
+ * 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.metadata.model.MetadataFacet;
+import org.apache.archiva.metadata.model.MetadataFacetFactory;
+
+/**
+ * @author Martin Stockhammer <ma...@apache.org>
+ */
+public abstract class AbstractMetadataFacetFactory<T extends MetadataFacet> implements MetadataFacetFactory<T>
+{
+    private final String facetId;
+    private final Class<T> facetClazz;
+
+    protected AbstractMetadataFacetFactory( Class<T> facetClazz, String facetId) {
+        this.facetId = facetId;
+        this.facetClazz = facetClazz;
+    }
+
+    protected AbstractMetadataFacetFactory(Class<T> facetClazz ) {
+        this.facetClazz = facetClazz;
+        try
+        {
+            this.facetId = (String) this.facetClazz.getField( "FACET_ID" ).get(null);
+        }
+        catch ( Throwable e)
+        {
+            throw new RuntimeException( "There is no FACET_ID static public field on the class " + facetClazz );
+        }
+    }
+
+    @Override
+    public abstract T createMetadataFacet( );
+
+    @Override
+    public abstract T createMetadataFacet( String repositoryId, String name );
+
+    @Override
+    public Class<T> getFacetClass( )
+    {
+        return facetClazz;
+    }
+
+    @Override
+    public String getFacetId( )
+    {
+        return facetId;
+    }
+}
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 5048353..c35d5f9 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
@@ -24,61 +24,187 @@ import org.apache.archiva.metadata.model.MetadataFacet;
 import org.apache.archiva.metadata.model.ProjectMetadata;
 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
 import org.apache.archiva.metadata.model.ProjectVersionReference;
+import org.apache.maven.index_shaded.lucene.util.packed.DirectMonotonicReader;
 
+import java.time.LocalDateTime;
+import java.time.ZonedDateTime;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
+import java.util.stream.Stream;
 
+/**
+ * A Metadata repository provides information about artifact metadata. It does not provide the artifact data itself.
+ * It may be possible to use the same backend for metadata and storage, but this depends on the backends and they are
+ * provided by different APIs.
+ *
+ * The motivation for this API is to provide fast access to the repository metadata and fulltext search. Also dependencies
+ * are stored in this repository.
+ *
+ * The methods here do not update the artifacts itself. They are only updating the data in the metadata repository.
+ * That means, if you want to update some artifact, you should make sure to update the artifact itself and the metadata
+ * repository (either directly or by repository scanning).
+ *
+ * Currently we are providing JCR, File based and Cassandra as backend for the metadata.
+ *
+ * The metadata repository uses sessions for accessing the data. Please make sure to always close the sessions after using it.
+ * Best idiom for using the sessions:
+ * <code>
+ * try(RepositorySession session = sessionFactory.createSession() {
+ *     // do your stuff
+ * }
+ * </code>
+ *
+ * It is implementation dependent, if the sessions are really used by the backend. E.g. the file based implementation ignores
+ * the sessions completely.
+ *
+ * Sessions should be closed immediately after usage. If it is expensive to open a session for a given backend. The backend
+ * should provide a session pool if possible. There are methods for refreshing a session if needed.
+ *
+ * You should avoid stacking sessions, that means, do not create a new session in the same thread, when a session is opened already.
+ *
+ * Some backend implementations (JCR) update the metadata in the background, that means update of the metadata is not reflected
+ * immediately.
+ *
+ * The base metadata coordinates are:
+ * <ul>
+ *     <li>Repository ID: The identifier of the repository, where the artifact resides</li>
+ *     <li>Namespace: This is a hierarchical coordinate for locating the projects. E.g. this corresponds to the groupId in maven. </li>
+ *     <li>Project ID: The project itself</li>
+ *     <li>Version: Each project may have different versions.</li>
+ *     <li>Artifact: Artifacts correspond to files / blob data. Each artifact has additional metadata, like name, version, modification time, ...</li>
+ * </ul>
+ *
+ * As the repository connects to some backend either locally or remote, the access to the repository may fail. The methods capsule the
+ * backend errors into <code>{@link MetadataRepositoryException}</code>.
+ *
+ * Facets are the way to provide additional metadata that is not part of the base API. It depends on the repository type (e.g. Maven, NPM,
+ * not the metadata backend) what facets are stored in addition to the standard metadata.
+ * Facets have a specific facet ID that represents the schema for the data stored. For creating specific objects for a given
+ * facet id the <code>{@link org.apache.archiva.metadata.model.MetadataFacetFactory}</code> is used.
+ * For each facet id there may exist multiple facet instances on each level. Facet instances are identified by their name, which may be
+ * a hierarchical path.
+ * The data in each facet instance is stored in properties (key-value pairs). The properties are converted into / from the specific
+ * facet object.
+ *
+ * Facets can be stored on repository, project, version and artifact level.
+ *
+ */
 public interface MetadataRepository
 {
     /**
-     * Update metadata for a particular project in the metadata repository, or create it if it does not already exist.
+     * Update metadata for a particular project in the metadata repository, or create it, if it does not already exist.
      *
-     * @param session
+     * @param session The session used for updating.
      * @param repositoryId the repository the project is in
      * @param project      the project metadata to create or update
+     * @throws MetadataRepositoryException if the update fails
      */
     void updateProject( RepositorySession session, String repositoryId, ProjectMetadata project )
         throws MetadataRepositoryException;
 
+    /**
+     * Update the metadata of a given artifact. If the artifact, namespace, version, project does not exist in the repository it will be created.
+     *
+     * @param session The repository session
+     * @param repositoryId The repository id
+     * @param namespace The namespace ('.' separated)
+     * @param projectId The project id
+     * @param projectVersion The project version
+     * @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 )
         throws MetadataRepositoryException;
 
+    /**
+     * Updates the metadata for a specific version of a given project. If the namespace, project, version does not exist,
+     * it will be created.
+     *
+     * @param session The repository session
+     * @param repositoryId The repository id
+     * @param namespace The namespace ('.' separated)
+     * @param projectId The project id
+     * @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 )
         throws MetadataRepositoryException;
 
     /**
-     * create the namespace in the repository. (if not exist)
+     * Create the namespace in the repository, if it does not exist.
+     * Namespaces do not have specific metadata attached.
      *
-     *
-     * @param session
-     * @param repositoryId
-     * @param namespace
-     * @throws MetadataRepositoryException
+     * @param session The repository session
+     * @param repositoryId The repository id
+     * @param namespace The namespace ('.' separated)
+     * @throws MetadataRepositoryException if something goes wrong during update
      */
     void updateNamespace( RepositorySession session, String repositoryId, String namespace )
         throws MetadataRepositoryException;
 
+    /**
+     * Return the facet names stored for the given facet id on the repository level.
+     *
+     * @param session The repository session
+     * @param repositoryId The repository id
+     * @param facetId The facet id
+     * @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 )
         throws MetadataRepositoryException;
 
+    <T extends MetadataFacet> Stream<T> getMetadataFacetStream( RepositorySession session, String repositoryId, Class<T> facetClazz)
+        throws MetadataRepositoryException;
+
+    <T extends MetadataFacet> Stream<T> getMetadataFacetStream( RepositorySession session, String repositoryId, Class<T> facetClazz, long offset, long maxEntries)
+        throws MetadataRepositoryException;
+
     /**
+     * Returns true, if there is facet data stored for the given id on the repository. The facet data itself
+     * may be empty. It's just checking if there is data stored for the given facet id.
      *
-     * @param session
-     * @param repositoryId
-     * @param facetId
-     * @return true if the repository datas for this facetId
-     * @throws MetadataRepositoryException
+     * @param session The repository session
+     * @param repositoryId The repository id
+     * @param facetId The facet id
+     * @return true if there is data stored this facetId on repository level.
+     * @throws MetadataRepositoryException if something goes wrong
      * @since 1.4-M4
      */
     boolean hasMetadataFacet( RepositorySession session, String repositoryId, String facetId )
         throws MetadataRepositoryException;
 
+    /**
+     * Returns the facet data stored on the repository level. The facet instance is identified by the facet id and the
+     * facet name. The returned object is a instance created by using <code>{@link org.apache.archiva.metadata.model.MetadataFacetFactory}</code>.
+     *
+     * @param session The repository session
+     * @param repositoryId The repository id
+     * @param facetId The facet id
+     * @param name The attribute name
+     * @return The facet values
+     * @throws MetadataRepositoryException if something goes wrong.
+     */
     MetadataFacet getMetadataFacet( RepositorySession session, String repositoryId, String facetId, String name )
         throws MetadataRepositoryException;
 
+    /**
+     * Returns the facet instance using the proper class.
+     *
+     * @param session The repository session
+     * @param repositoryId The repository
+     * @param clazz The facet object class
+     * @param name The name of the facet
+     * @param <T> The facet object
+     * @return The facet instance if it exists.
+     * @throws MetadataRepositoryException
+     */
+    <T extends MetadataFacet> T getMetadataFacet(RepositorySession session, String repositoryId, Class<T> clazz, String name)
+    throws MetadataRepositoryException;
+
     void addMetadataFacet( RepositorySession session, String repositoryId, MetadataFacet metadataFacet )
         throws MetadataRepositoryException;
 
@@ -102,6 +228,13 @@ public interface MetadataRepository
     List<ArtifactMetadata> getArtifactsByDateRange( RepositorySession session, String repositoryId, Date startTime, Date endTime )
         throws MetadataRepositoryException;
 
+    Stream<ArtifactMetadata> getArtifactsByDateRangeStream( RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime )
+        throws MetadataRepositoryException;
+
+    Stream<ArtifactMetadata> getArtifactsByDateRangeStream( RepositorySession session, String repositoryId,
+                                                            ZonedDateTime startTime, ZonedDateTime endTime, long offset, long maxEntries )
+        throws MetadataRepositoryException;
+
     Collection<ArtifactMetadata> getArtifactsByChecksum( RepositorySession session, String repositoryId, String checksum )
         throws MetadataRepositoryException;
 
diff --git a/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/MetadataResolver.java b/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/MetadataResolver.java
index 4cd2cfd..aae2cf0 100644
--- a/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/MetadataResolver.java
+++ b/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/MetadataResolver.java
@@ -22,11 +22,19 @@ package org.apache.archiva.metadata.repository;
 import org.apache.archiva.metadata.model.ArtifactMetadata;
 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
 import org.apache.archiva.metadata.model.ProjectVersionReference;
+import org.apache.archiva.repository.Repository;
+import org.apache.archiva.repository.RepositoryType;
 
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
 
 public interface MetadataResolver
 {
+    default List<RepositoryType> supportsRepositoryTypes() {
+        return Arrays.asList( RepositoryType.MAVEN );
+    }
+
     ProjectVersionMetadata resolveProjectVersion( RepositorySession session, String repoId, String namespace,
                                                   String projectId, String projectVersion )
         throws MetadataResolutionException;
diff --git a/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/MetadataService.java b/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/MetadataService.java
new file mode 100644
index 0000000..21c4f04
--- /dev/null
+++ b/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/MetadataService.java
@@ -0,0 +1,100 @@
+package org.apache.archiva.metadata.repository;
+
+/*
+ * 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.metadata.model.MetadataFacet;
+import org.apache.archiva.metadata.model.MetadataFacetFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Service;
+
+import javax.inject.Inject;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Martin Stockhammer <ma...@apache.org>
+ */
+
+@SuppressWarnings( "SpringJavaInjectionPointsAutowiringInspection" )
+@Service("metadataService")
+public class MetadataService
+{
+
+    private Map<String, MetadataFacetFactory<? extends MetadataFacet>> facetFactories = new HashMap<>( );
+    private Map<Class<? extends MetadataFacet>, MetadataFacetFactory<? extends MetadataFacet>> facetFactoriesByClass = new HashMap<>( );
+    private Map<String, Class<? extends MetadataFacet>> reverseFactoryMap = new HashMap<>( );
+
+    private MetadataResolver metadataResolver = null;
+
+    @Inject
+    ApplicationContext applicationContext;
+
+
+    @Inject
+    public void setMetadataFacetFactories( List<MetadataFacetFactory> factoryList ) {
+        Map<String, MetadataFacetFactory<? extends MetadataFacet>> facetFactories = new HashMap<>( );
+        Map<Class<? extends MetadataFacet>, MetadataFacetFactory<? extends MetadataFacet>> facetFactoriesByClass = new HashMap<>( );
+        Map<String, Class<? extends MetadataFacet>> reverseFactoryMap = new HashMap<>( );
+        for (MetadataFacetFactory factory : factoryList) {
+            facetFactories.put( factory.getFacetId( ), factory );
+            facetFactoriesByClass.put( factory.getFacetClass( ), factory );
+            reverseFactoryMap.put( factory.getFacetId( ), factory.getFacetClass( ) );
+        }
+        this.facetFactories = facetFactories;
+        this.facetFactoriesByClass = facetFactoriesByClass;
+        this.reverseFactoryMap = reverseFactoryMap;
+    }
+
+    public <T extends MetadataFacet> MetadataFacetFactory<T> getFactory(Class<T> facetClazz) {
+        return (MetadataFacetFactory<T>) facetFactoriesByClass.get( facetClazz );
+    }
+
+    public MetadataFacetFactory<?> getFactory(String facetId) {
+        return facetFactories.get( facetId );
+    }
+
+    public Set<String> getSupportedFacets() {
+        return facetFactories.keySet( );
+    }
+
+    public boolean supportsFacet(Class<? extends MetadataFacet> facetClazz) {
+        return facetFactoriesByClass.containsKey( facetClazz );
+    }
+
+    public boolean supportsFacet(String facetId) {
+        return facetFactories.containsKey( facetId );
+    }
+
+    public Class<? extends MetadataFacet> getFactoryClassForId( String facetId ) {
+        return reverseFactoryMap.get( facetId );
+    }
+
+    // Lazy evaluation to avoid problems with circular dependencies during initialization
+    public MetadataResolver getMetadataResolver()
+    {
+        if ( this.metadataResolver == null && applicationContext!=null)
+        {
+            this.metadataResolver = applicationContext.getBean( MetadataResolver.class );
+        }
+        return this.metadataResolver;
+    }
+}
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 a5574d6..ea47a00 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
@@ -23,6 +23,7 @@ import junit.framework.TestCase;
 import org.apache.archiva.metadata.generic.GenericMetadataFacet;
 import org.apache.archiva.metadata.generic.GenericMetadataFacetFactory;
 import org.apache.archiva.metadata.model.*;
+import org.apache.archiva.metadata.model.facets.AbstractMetadataFacetFactory;
 import org.apache.archiva.repository.Repository;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
 import org.junit.Before;
@@ -35,6 +36,8 @@ import org.springframework.test.context.ContextConfiguration;
 
 import java.text.SimpleDateFormat;
 import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -139,46 +142,43 @@ public abstract class AbstractMetadataRepositoryTest
     }
 
 
-    public static Map<String, MetadataFacetFactory> createTestMetadataFacetFactories( )
+    public static List<MetadataFacetFactory> createTestMetadataFacetFactories( )
     {
-        Map<String, MetadataFacetFactory> factories = new HashMap<>( );
-        factories.put( TEST_FACET_ID, new MetadataFacetFactory( )
+        List<MetadataFacetFactory> factories = new ArrayList<>( );
+        factories.add( new MetadataFacetFactory<TestMetadataFacet>( )
         {
             @Override
-            public MetadataFacet createMetadataFacet( )
+            public TestMetadataFacet createMetadataFacet( )
             {
                 return new TestMetadataFacet( TEST_METADATA_VALUE );
             }
 
             @Override
-            public MetadataFacet createMetadataFacet( String repositoryId, String name )
+            public TestMetadataFacet createMetadataFacet( String repositoryId, String name )
             {
                 return new TestMetadataFacet( TEST_METADATA_VALUE );
             }
-        } );
 
-        // add to ensure we don't accidentally create an empty facet ID.
-        factories.put( "", new MetadataFacetFactory( )
-        {
             @Override
-            public MetadataFacet createMetadataFacet( )
+            public Class<TestMetadataFacet> getFacetClass( )
             {
-                return new TestMetadataFacet( "", TEST_VALUE );
+                return TestMetadataFacet.class;
             }
 
             @Override
-            public MetadataFacet createMetadataFacet( String repositoryId, String name )
+            public String getFacetId( )
             {
-                return new TestMetadataFacet( "", TEST_VALUE );
+                return TEST_FACET_ID;
             }
         } );
 
         // for the getArtifactsByProjectVersionMetadata tests
-        factories.put( GenericMetadataFacet.FACET_ID, new GenericMetadataFacetFactory( ) );
+        factories.add( new GenericMetadataFacetFactory( ) );
 
         return factories;
     }
 
+
     @Test
     public void testRootNamespaceWithNoMetadataRepository( )
         throws Exception
@@ -794,6 +794,22 @@ public abstract class AbstractMetadataRepositoryTest
     }
 
     @Test
+    public void testGetMetadataFacetByClass( )
+        throws Exception
+    {
+        try ( RepositorySession session = getSessionFactory( ).createSession( ) )
+        {
+            getRepository( ).addMetadataFacet( session, TEST_REPO_ID, new TestMetadataFacet( TEST_VALUE ) );
+
+            TestMetadataFacet test =
+                (TestMetadataFacet) getRepository( ).getMetadataFacet( session, TEST_REPO_ID, TestMetadataFacet.class, TEST_NAME );
+
+            assertEquals( new TestMetadataFacet( TEST_VALUE ), test );
+
+        }
+    }
+
+    @Test
     public void testGetMetadataFacetWhenEmpty( )
         throws Exception
     {
@@ -858,6 +874,28 @@ public abstract class AbstractMetadataRepositoryTest
     }
 
     @Test
+    public void testGetMetadataFacetsStream( )
+        throws Exception
+    {
+        try ( RepositorySession session = getSessionFactory( ).createSession( ) )
+        {
+            getRepository( ).addMetadataFacet( session, TEST_REPO_ID, new TestMetadataFacet( TEST_VALUE ) );
+        }
+
+        try ( RepositorySession session = getSessionFactory( ).createSession( ) )
+        {
+            tryAssert( ( ) -> {
+                Stream<TestMetadataFacet> str = getRepository( ).getMetadataFacetStream( session, TEST_REPO_ID, TestMetadataFacet.class );
+                assertNotNull( str );
+                List<TestMetadataFacet> result = str.collect( Collectors.toList( ) );
+                assertEquals( 1, result.size( ) );
+                assertEquals( TEST_NAME, result.get( 0 ).getName( ) );
+            } );
+
+        }
+    }
+
+    @Test
     public void testGetMetadataFacetsWhenEmpty( )
         throws Exception
     {
@@ -1617,7 +1655,7 @@ public abstract class AbstractMetadataRepositoryTest
                 assertThat( artifactMetadata.getRepositoryId( ) ).isEqualTo( TEST_REPO_ID );
                 MetadataFacet facet = artifactMetadata.getFacet( TEST_FACET_ID );
                 assertThat( facet ).isNotNull( );
-                assertThat( facet.toProperties( ) ).isEqualTo( Collections.singletonMap( "foo", TEST_METADATA_VALUE ) );
+                assertThat( facet.toProperties( ).get("foo").equals(TEST_METADATA_VALUE) );
             } );
         }
     }
diff --git a/archiva-modules/plugins/audit/src/main/java/org/apache/archiva/audit/AuditEventFactory.java b/archiva-modules/plugins/audit/src/main/java/org/apache/archiva/audit/AuditEventFactory.java
index 620100f..c76be7e 100644
--- a/archiva-modules/plugins/audit/src/main/java/org/apache/archiva/audit/AuditEventFactory.java
+++ b/archiva-modules/plugins/audit/src/main/java/org/apache/archiva/audit/AuditEventFactory.java
@@ -19,8 +19,8 @@ package org.apache.archiva.audit;
  * under the License.
  */
 
-import org.apache.archiva.metadata.model.MetadataFacet;
 import org.apache.archiva.metadata.model.MetadataFacetFactory;
+import org.apache.archiva.metadata.model.facets.AbstractMetadataFacetFactory;
 import org.apache.archiva.metadata.model.facets.AuditEvent;
 import org.springframework.stereotype.Service;
 
@@ -29,17 +29,33 @@ import org.springframework.stereotype.Service;
  */
 @Service("metadataFacetFactory#org.apache.archiva.audit")
 public class AuditEventFactory
-    implements MetadataFacetFactory
+    extends AbstractMetadataFacetFactory<AuditEvent>
 {
+    public AuditEventFactory() {
+        super( AuditEvent.class );
+    }
+
     @Override
-    public MetadataFacet createMetadataFacet()
+    public AuditEvent createMetadataFacet()
     {
         throw new UnsupportedOperationException( "Must construct an audit event with a name" );
     }
 
     @Override
-    public MetadataFacet createMetadataFacet( String repositoryId, String name )
+    public AuditEvent createMetadataFacet( String repositoryId, String name )
     {
         return new AuditEvent( name, repositoryId );
     }
+
+    @Override
+    public boolean assignsFacet( Class<?> clazz )
+    {
+        return false;
+    }
+
+    @Override
+    public Class<AuditEvent> getFacetClass( )
+    {
+        return null;
+    }
 }
diff --git a/archiva-modules/plugins/generic-metadata-support/src/main/java/org/apache/archiva/metadata/generic/GenericMetadataFacetFactory.java b/archiva-modules/plugins/generic-metadata-support/src/main/java/org/apache/archiva/metadata/generic/GenericMetadataFacetFactory.java
index 8d4dfb6..b5aad19 100644
--- a/archiva-modules/plugins/generic-metadata-support/src/main/java/org/apache/archiva/metadata/generic/GenericMetadataFacetFactory.java
+++ b/archiva-modules/plugins/generic-metadata-support/src/main/java/org/apache/archiva/metadata/generic/GenericMetadataFacetFactory.java
@@ -19,25 +19,28 @@ package org.apache.archiva.metadata.generic;
  * under the License.
  */
 
-import org.apache.archiva.metadata.model.MetadataFacet;
-import org.apache.archiva.metadata.model.MetadataFacetFactory;
+import org.apache.archiva.metadata.model.facets.AbstractMetadataFacetFactory;
 import org.springframework.stereotype.Service;
 
 /**
  */
 @Service("metadataFacetFactory#org.apache.archiva.metadata.generic")
 public class GenericMetadataFacetFactory
-    implements MetadataFacetFactory
+    extends AbstractMetadataFacetFactory<GenericMetadataFacet>
 {
 
+    public GenericMetadataFacetFactory() {
+        super( GenericMetadataFacet.class );
+    }
+
     @Override
-    public MetadataFacet createMetadataFacet()
+    public GenericMetadataFacet createMetadataFacet()
     {
         return new GenericMetadataFacet();
     }
 
     @Override
-    public MetadataFacet createMetadataFacet( String repositoryId, String name )
+    public GenericMetadataFacet createMetadataFacet( String repositoryId, String name )
     {
         throw new UnsupportedOperationException( "There is no valid name for project version facets" );
     }
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 00cef08..4a2c8b0 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
@@ -38,6 +38,7 @@ import org.apache.archiva.metadata.model.maven2.MavenArtifactFacet;
 import org.apache.archiva.metadata.repository.MetadataRepository;
 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
 import org.apache.archiva.metadata.repository.MetadataResolutionException;
+import org.apache.archiva.metadata.repository.MetadataService;
 import org.apache.archiva.metadata.repository.RepositorySession;
 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsProvider;
@@ -46,6 +47,7 @@ import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.commons.JcrUtils;
 import org.apache.jackrabbit.commons.cnd.CndImporter;
 import org.apache.jackrabbit.commons.cnd.ParseException;
+import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -57,10 +59,9 @@ import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.SimpleCredentials;
+import javax.jcr.Value;
 import javax.jcr.ValueFactory;
 import javax.jcr.Workspace;
-import javax.jcr.nodetype.NodeTypeManager;
-import javax.jcr.nodetype.NodeTypeTemplate;
 import javax.jcr.query.Query;
 import javax.jcr.query.QueryManager;
 import javax.jcr.query.QueryResult;
@@ -69,6 +70,7 @@ import javax.jcr.query.RowIterator;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
+import java.time.ZonedDateTime;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -82,10 +84,14 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 import static javax.jcr.Property.JCR_LAST_MODIFIED;
-import static org.apache.archiva.metadata.repository.jcr.JcrConstants.DEPENDENCY_NODE_TYPE;
-import static org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_VERSION_PROPERTIES;
+import static org.apache.archiva.metadata.repository.jcr.JcrConstants.*;
 
 /**
  * TODO below: revise storage format for project version metadata
@@ -96,34 +102,34 @@ public class JcrMetadataRepository
 {
 
 
-    private static final String QUERY_ARTIFACT_1 = "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE + "] AS artifact WHERE ISDESCENDANTNODE(artifact,'/";
+    private static final String QUERY_ARTIFACT_1 = "SELECT * FROM [" + ARTIFACT_NODE_TYPE + "] AS artifact WHERE ISDESCENDANTNODE(artifact,'/";
 
-    static final String QUERY_ARTIFACTS_BY_PROJECT_VERSION_1 = "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE + "] AS projectVersion INNER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE
-        + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) INNER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE
+    static final String QUERY_ARTIFACTS_BY_PROJECT_VERSION_1 = "SELECT * FROM [" + PROJECT_VERSION_NODE_TYPE + "] AS projectVersion INNER JOIN [" + ARTIFACT_NODE_TYPE
+        + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) INNER JOIN [" + FACET_NODE_TYPE
         + "] AS facet ON ISCHILDNODE(facet, projectVersion) WHERE ([facet].[";
     static final String QUERY_ARTIFACTS_BY_PROJECT_VERSION_2= "] = $value)";
 
-    static final String QUERY_ARTIFACTS_BY_METADATA_1 = "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE + "] AS artifact INNER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE
+    static final String QUERY_ARTIFACTS_BY_METADATA_1 = "SELECT * FROM [" + ARTIFACT_NODE_TYPE + "] AS artifact INNER JOIN [" + FACET_NODE_TYPE
         + "] AS facet ON ISCHILDNODE(facet, artifact) WHERE ([facet].[";
     static final String QUERY_ARTIFACTS_BY_METADATA_2 = "] = $value)";
 
-    static final String QUERY_ARTIFACTS_BY_PROPERTY_1 = "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE + "] AS projectVersion INNER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE
+    static final String QUERY_ARTIFACTS_BY_PROPERTY_1 = "SELECT * FROM [" + PROJECT_VERSION_NODE_TYPE + "] AS projectVersion INNER JOIN [" + ARTIFACT_NODE_TYPE
            + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) WHERE ([projectVersion].[";
     static final String QUERY_ARTIFACTS_BY_PROPERTY_2 = "] = $value)";
 
 
     private static final String QUERY_ARTIFACT_2 = "')";
 
-    private final Map<String, MetadataFacetFactory> metadataFacetFactories;
+    private MetadataService metadataService;
 
     private Logger log = LoggerFactory.getLogger( JcrMetadataRepository.class );
 
     private Repository repository;
 
-    public JcrMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories, Repository repository )
+    public JcrMetadataRepository( MetadataService metadataService, Repository repository )
         throws RepositoryException
     {
-        this.metadataFacetFactories = metadataFacetFactories;
+        this.metadataService = metadataService;
         this.repository = repository;
     }
 
@@ -146,7 +152,6 @@ public class JcrMetadataRepository
             registry.registerNamespace( "archiva", "http://archiva.apache.org/jcr/" );
         }
 
-        NodeTypeManager nodeTypeManager = workspace.getNodeTypeManager();
         try(
             Reader cndReader = new InputStreamReader(
                 Thread.currentThread( ).getContextClassLoader( ).getResourceAsStream( "org/apache/archiva/metadata/repository/jcr/jcr-schema.cnd" ) ))
@@ -162,31 +167,6 @@ public class JcrMetadataRepository
             e.printStackTrace( );
         }
 
-
-//        registerMixinNodeType( nodeTypeManager, REPOSITORY_NODE_TYPE );
-//        registerMixinNodeType( nodeTypeManager, NAMESPACE_NODE_TYPE );
-//        registerMixinNodeType( nodeTypeManager, PROJECT_NODE_TYPE );
-//        registerMixinNodeType( nodeTypeManager, PROJECT_VERSION_NODE_TYPE );
-//        registerMixinNodeType( nodeTypeManager, ARTIFACT_NODE_TYPE );
-//        registerMixinNodeType( nodeTypeManager, FACET_NODE_TYPE );
-//        registerMixinNodeType( nodeTypeManager, DEPENDENCY_NODE_TYPE );
-
-
-    }
-
-    private static void registerMixinNodeType( NodeTypeManager nodeTypeManager, String name )
-        throws RepositoryException
-    {
-        // for now just don't re-create - but in future if we change the definition, make sure to remove first as an
-        // upgrade path
-        if ( !nodeTypeManager.hasNodeType( name ) )
-        {
-            NodeTypeTemplate nodeType = nodeTypeManager.createNodeTypeTemplate();
-            nodeType.setMixin( true );
-            nodeType.setName( name );
-            nodeType.setQueryable( true );
-            nodeTypeManager.registerNodeType( nodeType, false );
-        }
     }
 
     private Session getSession(RepositorySession repositorySession) throws MetadataRepositoryException {
@@ -249,7 +229,7 @@ public class JcrMetadataRepository
             node.setProperty( "version", artifactMeta.getVersion() );
 
             // iterate over available facets to update/add/remove from the artifactMetadata
-            for ( String facetId : metadataFacetFactories.keySet() )
+            for ( String facetId : metadataService.getSupportedFacets() )
             {
                 MetadataFacet metadataFacet = artifactMeta.getFacet( facetId );
                 if ( metadataFacet == null )
@@ -264,7 +244,8 @@ public class JcrMetadataRepository
                 {
                     // recreate, to ensure properties are removed
                     Node n = node.addNode( facetId);
-                    n.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE );
+                    n.addMixin( FACET_NODE_TYPE );
+                    n.setProperty( "facetId", facetId );
 
                     for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
                     {
@@ -397,7 +378,7 @@ public class JcrMetadataRepository
                     versionNode.getNode( facet.getFacetId() ).remove();
                 }
                 Node n = versionNode.addNode( facet.getFacetId() );
-                n.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE );
+                n.addMixin( FACET_NODE_TYPE );
 
                 for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
                 {
@@ -513,6 +494,84 @@ public class JcrMetadataRepository
         return facets;
     }
 
+    private <T> Spliterator<T> createResultSpliterator(QueryResult result, Function<Row, T> converter) throws MetadataRepositoryException
+    {
+        final RowIterator rowIterator;
+        try
+        {
+            rowIterator = result.getRows();
+        }
+        catch ( RepositoryException e )
+        {
+            throw new MetadataRepositoryException( e.getMessage( ), e );
+        }
+        return new Spliterator<T>( )
+        {
+            @Override
+            public boolean tryAdvance( Consumer<? super T> action )
+            {
+                while (rowIterator.hasNext()) {
+                    T item = converter.apply( rowIterator.nextRow() );
+                    if (item!=null)
+                    {
+                        action.accept( item );
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            @Override
+            public Spliterator<T> trySplit( )
+            {
+                return null;
+            }
+
+            @Override
+            public long estimateSize( )
+            {
+                return 0;
+            }
+
+            @Override
+            public int characteristics( )
+            {
+                return ORDERED+NONNULL;
+            }
+        };
+    }
+
+    @Override
+    public <T extends MetadataFacet> Stream<T> getMetadataFacetStream( RepositorySession session, String repositoryId, Class<T> facetClazz ) throws MetadataRepositoryException
+    {
+        final Session jcrSession = getSession( session );
+        final MetadataFacetFactory<T> factory = metadataService.getFactory( facetClazz );
+        final String facetId = factory.getFacetId( );
+        final String facetPath = getFacetPath( repositoryId, facetId );
+        String q = "SELECT * FROM ["+FACET_NODE_TYPE+"] AS facet WHERE ISDESCENDANTNODE(facet, [/"+facetPath+"])";
+        Map<String, String> params = new HashMap<>( );
+        QueryResult result = runNativeJcrQuery( jcrSession, q, params );
+        return StreamSupport.stream( createResultSpliterator( result, (Row row)-> {
+            try
+            {
+                Node node = row.getNode( "facet" );
+                String path = StringUtils.removeStart( node.getPath(), facetPath);
+                return createFacet( factory, node, repositoryId, path );
+            }
+            catch ( RepositoryException e )
+            {
+                return null;
+            }
+        }), false );
+
+    }
+
+    @Override
+    public <T extends MetadataFacet> Stream<T> getMetadataFacetStream( RepositorySession session, String repositoryId, Class<T> facetClazz, long offset, long maxEntries ) throws MetadataRepositoryException
+    {
+        return null;
+    }
+
     private void recurse( List<String> facets, String prefix, Node node )
         throws RepositoryException
     {
@@ -531,37 +590,28 @@ public class JcrMetadataRepository
         }
     }
 
+
     @Override
-    public MetadataFacet getMetadataFacet( RepositorySession session, String repositoryId, String facetId, String name )
-        throws MetadataRepositoryException
+    public <T extends MetadataFacet> T getMetadataFacet( RepositorySession session, String repositoryId, Class<T> clazz, String name ) throws MetadataRepositoryException
     {
+        if (!metadataService.supportsFacet( clazz )) {
+            log.warn( "The required metadata class is not supported: " + clazz );
+            return null;
+        }
         final Session jcrSession = getSession( session );
-        MetadataFacet metadataFacet = null;
+        final MetadataFacetFactory<T> factory = metadataService.getFactory( clazz );
+        final String facetId = factory.getFacetId( );
         try
         {
             Node root = jcrSession.getRootNode();
             Node node = root.getNode( getFacetPath( repositoryId, facetId, name ) );
 
-            if ( metadataFacetFactories == null )
+            if ( metadataService.getSupportedFacets().size()==0)
             {
-                return metadataFacet;
+                return null;
             }
 
-            MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
-            if ( metadataFacetFactory != null )
-            {
-                metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
-                Map<String, String> map = new HashMap<>();
-                for ( Property property : JcrUtils.getProperties( node ) )
-                {
-                    String p = property.getName();
-                    if ( !p.startsWith( "jcr:" ) )
-                    {
-                        map.put( p, property.getString() );
-                    }
-                }
-                metadataFacet.fromProperties( map );
-            }
+            return createFacet( factory, node, repositoryId, name );
         }
         catch ( PathNotFoundException e )
         {
@@ -571,7 +621,35 @@ public class JcrMetadataRepository
         {
             throw new MetadataRepositoryException( e.getMessage(), e );
         }
-        return metadataFacet;
+        return null;
+    }
+
+    @Nullable
+    private <T extends MetadataFacet> T createFacet( MetadataFacetFactory<T> factory, Node node, String repositoryId, String name ) throws RepositoryException
+    {
+        if ( factory != null )
+        {
+            T metadataFacet = factory.createMetadataFacet( repositoryId, name );
+            Map<String, String> map = new HashMap<>();
+            for ( Property property : JcrUtils.getProperties( node ) )
+            {
+                String p = property.getName();
+                if ( !p.startsWith( "jcr:" ) )
+                {
+                    map.put( p, property.getString() );
+                }
+            }
+            metadataFacet.fromProperties( map );
+            return metadataFacet;
+        }
+        return null;
+    }
+
+    @Override
+    public MetadataFacet getMetadataFacet( RepositorySession session, String repositoryId, String facetId, String name )
+        throws MetadataRepositoryException
+    {
+        return getMetadataFacet( session, repositoryId, metadataService.getFactoryClassForId( facetId ), name );
     }
 
     @Override
@@ -588,6 +666,11 @@ public class JcrMetadataRepository
             Node facetNode = JcrUtils.getOrAddNode( facets, id );
 
             Node node = getOrAddNodeByPath( facetNode, metadataFacet.getName() );
+            if (!node.isNodeType( FACET_NODE_TYPE ))
+            {
+                node.addMixin( FACET_NODE_TYPE );
+                node.setProperty( "facetId", id );
+            }
 
             for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
             {
@@ -718,6 +801,18 @@ public class JcrMetadataRepository
         return artifacts;
     }
 
+    @Override
+    public Stream<ArtifactMetadata> getArtifactsByDateRangeStream( RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime ) throws MetadataRepositoryException
+    {
+        return null;
+    }
+
+    @Override
+    public Stream<ArtifactMetadata> getArtifactsByDateRangeStream( RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime, long offset, long maxEntries ) throws MetadataRepositoryException
+    {
+        return null;
+    }
+
 
     @Override
     public List<ArtifactMetadata> getArtifactsByChecksum( RepositorySession session, String repositoryId, String checksum )
@@ -804,13 +899,18 @@ public class JcrMetadataRepository
 
         try
         {
+            log.debug( "Query: {}", q );
             Query query = jcrSession.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
             ValueFactory valueFactory = jcrSession.getValueFactory();
             for ( Entry<String, String> entry : bindings.entrySet() )
             {
-                query.bindValue( entry.getKey(), valueFactory.createValue( entry.getValue() ) );
+                log.debug( "Binding: {}={}", entry.getKey( ), entry.getValue( ) );
+                Value value = valueFactory.createValue( entry.getValue( ) );
+                log.debug( "Binding value {}={}", entry.getKey( ), value);
+                query.bindValue( entry.getKey(), value );
             }
             long start = System.currentTimeMillis( );
+            log.debug( "Execute query {}", query );
             QueryResult result = query.execute();
             long end = System.currentTimeMillis( );
             log.info( "JCR Query ran in {} milliseconds: {}", end - start, q );
@@ -889,7 +989,7 @@ public class JcrMetadataRepository
             artifacts = new ArrayList<>();
             for ( Node n : JcrUtils.getNodes( result ) )
             {
-                if ( n.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE ) )
+                if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
                 {
                     artifacts.add( getArtifactFromNode( repositoryId, n ) );
                 }
@@ -1109,10 +1209,10 @@ public class JcrMetadataRepository
     {
         for ( Node n : JcrUtils.getChildNodes( node ) )
         {
-            if ( n.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE ) )
+            if ( n.isNodeType( FACET_NODE_TYPE ) )
             {
                 String name = n.getName();
-                MetadataFacetFactory factory = metadataFacetFactories.get( name );
+                MetadataFacetFactory factory = metadataService.getFactory( name );
                 if ( factory == null )
                 {
                     log.error( "Attempted to load unknown project version metadata facet: {}", name );
@@ -1278,7 +1378,7 @@ public class JcrMetadataRepository
     {
         try
         {
-            return getNodeNames( getSession(session), getProjectPath( repositoryId, namespace, projectId ), org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE );
+            return getNodeNames( getSession(session), getProjectPath( repositoryId, namespace, projectId ), PROJECT_VERSION_NODE_TYPE );
         }
         catch ( MetadataRepositoryException e )
         {
@@ -1306,7 +1406,7 @@ public class JcrMetadataRepository
 
                 for ( Node n : JcrUtils.getChildNodes( node ) )
                 {
-                    if ( n.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE ) )
+                    if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
                     {
                         if ( n.hasProperty( "version" ) )
                         {
@@ -1345,7 +1445,7 @@ public class JcrMetadataRepository
 
             for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
             {
-                if ( node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE ) && StringUtils.equals( projectVersion,
+                if ( node.isNodeType( PROJECT_VERSION_NODE_TYPE ) && StringUtils.equals( projectVersion,
                                                                                          node.getName() ) )
                 {
                     node.remove();
@@ -1381,7 +1481,7 @@ public class JcrMetadataRepository
 
             for ( Node node : JcrUtils.getChildNodes( nodeAtPath ) )
             {
-                if ( node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE ) //
+                if ( node.isNodeType( PROJECT_VERSION_NODE_TYPE ) //
                     && StringUtils.equals( node.getName(), projectVersion ) )
                 {
                     node.remove();
@@ -1411,7 +1511,7 @@ public class JcrMetadataRepository
 
                 for ( Node n : JcrUtils.getChildNodes( node ) )
                 {
-                    if ( n.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE ) )
+                    if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
                     {
                         ArtifactMetadata artifactMetadata = getArtifactFromNode( repositoryId, n );
                         log.debug( "artifactMetadata: {}", artifactMetadata );
@@ -1457,7 +1557,7 @@ public class JcrMetadataRepository
 
                 for ( Node n : JcrUtils.getChildNodes( node ) )
                 {
-                    if ( n.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE ) )
+                    if ( n.isNodeType( ARTIFACT_NODE_TYPE ) )
                     {
                         artifacts.add( getArtifactFromNode( repositoryId, n ) );
                     }
@@ -1526,15 +1626,15 @@ public class JcrMetadataRepository
         {
             // We search only for project version properties if the key is a valid property name
             String q1 =
-                "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE
-                    + "] AS projectVersion LEFT OUTER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE
+                "SELECT * FROM [" + PROJECT_VERSION_NODE_TYPE
+                    + "] AS projectVersion LEFT OUTER JOIN [" + ARTIFACT_NODE_TYPE
                     + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) WHERE " + projectVersionCondition + descendantCondition;
              result.addAll(runJcrQuery( jcrSession, repositoryId, q1, ImmutableMap.of( "value", text ), false ));
         }
         String q2 =
-            "SELECT * FROM [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE
-                + "] AS projectVersion LEFT OUTER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE
-                + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) LEFT OUTER JOIN [" + org.apache.archiva.metadata.repository.jcr.JcrConstants.FACET_NODE_TYPE
+            "SELECT * FROM [" + PROJECT_VERSION_NODE_TYPE
+                + "] AS projectVersion LEFT OUTER JOIN [" + ARTIFACT_NODE_TYPE
+                + "] AS artifact ON ISCHILDNODE(artifact, projectVersion) LEFT OUTER JOIN [" + FACET_NODE_TYPE
                 + "] AS facet ON ISCHILDNODE(facet, projectVersion) WHERE " + facetCondition + descendantCondition;
         result.addAll( runJcrQuery( jcrSession, repositoryId, q2, ImmutableMap.of( "value", text ), false ) );
         return result;
@@ -1639,7 +1739,8 @@ public class JcrMetadataRepository
 
     private static String getFacetPath( String repositoryId, String facetId )
     {
-        return getRepositoryPath( repositoryId ) + "/facets/" + facetId;
+        return StringUtils.isEmpty( facetId ) ? getRepositoryPath( repositoryId ) + "/facets" :
+            getRepositoryPath( repositoryId ) + "/facets/" + facetId;
     }
 
     private static String getNamespacePath( String repositoryId, String namespace )
@@ -1748,9 +1849,9 @@ public class JcrMetadataRepository
         Node projectNode = getOrAddProjectNode( jcrSession, repositoryId, namespace, projectId );
         log.debug( "Project node {}", projectNode );
         Node projectVersionNode = JcrUtils.getOrAddNode( projectNode, projectVersion, JcrConstants.NT_UNSTRUCTURED);
-        if (!projectVersionNode.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE ))
+        if (!projectVersionNode.isNodeType( PROJECT_VERSION_NODE_TYPE ))
         {
-            projectVersionNode.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE );
+            projectVersionNode.addMixin( PROJECT_VERSION_NODE_TYPE );
         }
         if (!projectVersionNode.hasProperty( "id" ))
         {
@@ -1767,9 +1868,9 @@ public class JcrMetadataRepository
     {
         Node versionNode = getOrAddProjectVersionNode( jcrSession, repositoryId, namespace, projectId, projectVersion );
         Node node = JcrUtils.getOrAddNode( versionNode, id);
-        if (!node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE ))
+        if (!node.isNodeType( ARTIFACT_NODE_TYPE ))
         {
-            node.addMixin( org.apache.archiva.metadata.repository.jcr.JcrConstants.ARTIFACT_NODE_TYPE );
+            node.addMixin( ARTIFACT_NODE_TYPE );
         }
         if (!node.hasProperty( "id" )) {
             node.setProperty( "id", id );
diff --git a/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/JcrRepositorySessionFactory.java b/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/JcrRepositorySessionFactory.java
index f1f6798..0469b87 100644
--- a/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/JcrRepositorySessionFactory.java
+++ b/archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/JcrRepositorySessionFactory.java
@@ -19,6 +19,7 @@ package org.apache.archiva.metadata.repository.jcr;
  * under the License.
  */
 
+import org.apache.archiva.metadata.model.MetadataFacet;
 import org.apache.archiva.metadata.model.MetadataFacetFactory;
 import org.apache.archiva.metadata.repository.*;
 import org.apache.commons.lang.StringUtils;
@@ -49,11 +50,6 @@ public class JcrRepositorySessionFactory extends AbstractRepositorySessionFactor
 
     private Logger logger = LoggerFactory.getLogger( getClass() );
 
-    @Inject
-    private ApplicationContext applicationContext;
-
-    private Map<String, MetadataFacetFactory> metadataFacetFactories;
-
     private Repository repository;
 
     // Lazy evaluation to avoid problems with circular dependencies during initialization
@@ -62,6 +58,9 @@ public class JcrRepositorySessionFactory extends AbstractRepositorySessionFactor
     @Inject
     private RepositorySessionFactoryBean repositorySessionFactoryBean;
 
+    @Inject
+    private MetadataService metadataService;
+
     private OakRepositoryFactory repositoryFactory;
 
     private JcrMetadataRepository jcrMetadataRepository;
@@ -80,14 +79,8 @@ public class JcrRepositorySessionFactory extends AbstractRepositorySessionFactor
         }
     }
 
-    // Lazy evaluation to avoid problems with circular dependencies during initialization
-    private MetadataResolver getMetadataResolver()
-    {
-        if ( this.metadataResolver == null && applicationContext!=null)
-        {
-            this.metadataResolver = applicationContext.getBean( MetadataResolver.class );
-        }
-        return this.metadataResolver;
+    private MetadataResolver getMetadataResolver() {
+        return metadataService.getMetadataResolver( );
     }
 
     protected void initialize()
@@ -102,27 +95,6 @@ public class JcrRepositorySessionFactory extends AbstractRepositorySessionFactor
         StopWatch stopWatch = new StopWatch();
         stopWatch.start();
 
-        if (applicationContext!=null) {
-            metadataFacetFactories = applicationContext.getBeansOfType(MetadataFacetFactory.class);
-        }
-        // olamy with spring the "id" is now "metadataFacetFactory#hint"
-        // whereas was only hint with plexus so let remove  metadataFacetFactory#
-        Map<String, MetadataFacetFactory> cleanedMetadataFacetFactories =
-            new HashMap<>( metadataFacetFactories.size() );
-
-        for ( Map.Entry<String, MetadataFacetFactory> entry : metadataFacetFactories.entrySet() )
-        {
-            if (entry.getKey().contains("#")) {
-                cleanedMetadataFacetFactories.put( StringUtils.substringAfterLast( entry.getKey(), "#" ),
-                        entry.getValue() );
-
-            } else {
-                cleanedMetadataFacetFactories.put(entry.getKey(), entry.getValue());
-            }
-        }
-
-        metadataFacetFactories = cleanedMetadataFacetFactories;
-
         try
         {
 
@@ -136,7 +108,7 @@ public class JcrRepositorySessionFactory extends AbstractRepositorySessionFactor
                 logger.error("Repository creation failed {}", e.getMessage());
                 throw new RuntimeException("Fatal error. Could not create metadata repository.");
             }
-            jcrMetadataRepository = new JcrMetadataRepository( metadataFacetFactories, repository );
+            jcrMetadataRepository = new JcrMetadataRepository( metadataService, repository );
             try ( JcrRepositorySession session = new JcrRepositorySession( jcrMetadataRepository, metadataResolver )) {
                 JcrMetadataRepository.initializeNodeTypes( session.getJcrSession() );
                 // Saves automatically with close
@@ -171,8 +143,14 @@ public class JcrRepositorySessionFactory extends AbstractRepositorySessionFactor
         return jcrMetadataRepository;
     }
 
-    public void setMetadataFacetFactories(Map<String, MetadataFacetFactory> metadataFacetFactories) {
-        this.metadataFacetFactories = metadataFacetFactories;
+
+    public MetadataService getMetadataService( )
+    {
+        return metadataService;
     }
 
+    public void setMetadataService( MetadataService metadataService )
+    {
+        this.metadataService = metadataService;
+    }
 }
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 677bf27..e9982dc 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
@@ -419,7 +419,6 @@ public class OakRepositoryFactory
 
             private IndexDefinitionBuilder.PropertyRule initBaseRule( IndexDefinitionBuilder.IndexRule rule ) {
                 return rule
-                    .sync()
                     .indexNodeName( )
                     .property(JCR_CREATED).propertyIndex().type("Date").ordered()
                     .property(JCR_LASTMODIFIED ).propertyIndex().type( "Date" ).ordered()
@@ -486,7 +485,8 @@ public class OakRepositoryFactory
                         .property( "whenGathered" ).type("Date").propertyIndex().analyzed().ordered()
                         .property("size").type("Long").propertyIndex().analyzed().ordered()
                         .property("version").propertyIndex().analyzed().ordered();
-                    initRegexAll( idxBuilder.indexRule( FACET_NODE_TYPE ) );
+                    initRegexAll( idxBuilder.indexRule( FACET_NODE_TYPE ) )
+                        .property("facetId").propertyIndex().analyzed().ordered();
                     idxBuilder.indexRule( MIXIN_META_SCM )
                         .property( "scm.connection" ).propertyIndex()
                         .property( "scm.developerConnection" ).propertyIndex()
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 e63d5fd..9b56d3f 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
@@ -105,4 +105,5 @@
  + checksum (archiva:checksum) multiple
  + * (archiva:facet) multiple
 
-[archiva:facet] > archiva:base mixin
\ No newline at end of file
+[archiva:facet] > archiva:base mixin
+ - facetId
\ No newline at end of file
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 171d6be..58bb441 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
@@ -24,6 +24,7 @@ import org.apache.archiva.metadata.model.MetadataFacetFactory;
 import org.apache.archiva.metadata.repository.AbstractMetadataRepositoryTest;
 import org.apache.archiva.metadata.repository.DefaultMetadataResolver;
 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
+import org.apache.archiva.metadata.repository.MetadataService;
 import org.apache.archiva.metadata.repository.MetadataSessionException;
 import org.apache.archiva.metadata.repository.RepositorySession;
 import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException;
@@ -32,21 +33,15 @@ import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
-import javax.jcr.query.QueryResult;
-import javax.jcr.query.Row;
-import javax.jcr.query.RowIterator;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Collection;
-import java.util.Map;
+import java.util.List;
 
-import static org.apache.archiva.metadata.repository.jcr.JcrConstants.PROJECT_VERSION_NODE_TYPE;
 import static org.assertj.core.api.Assertions.assertThat;
 
 /**
@@ -81,10 +76,12 @@ public class JcrMetadataRepositoryTest
             org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
         }
 
-        Map<String, MetadataFacetFactory> factories = createTestMetadataFacetFactories( );
+        List<MetadataFacetFactory> factories = createTestMetadataFacetFactories( );
+        MetadataService metadataService = new MetadataService();
+        metadataService.setMetadataFacetFactories( factories );
         JcrRepositorySessionFactory jcrSessionFactory = new JcrRepositorySessionFactory( );
         jcrSessionFactory.setMetadataResolver( new DefaultMetadataResolver( ) );
-        jcrSessionFactory.setMetadataFacetFactories( factories );
+        jcrSessionFactory.setMetadataService( metadataService );
 
         jcrSessionFactory.open( );
         sessionFactory = jcrSessionFactory;
diff --git a/archiva-modules/plugins/metadata-store-jcr/src/test/java/org/apache/archiva/metadata/repository/stats/JcrRepositoryStatisticsGatheringTest.java b/archiva-modules/plugins/metadata-store-jcr/src/test/java/org/apache/archiva/metadata/repository/stats/JcrRepositoryStatisticsGatheringTest.java
index 6fe7da2..7e1e83d 100644
--- a/archiva-modules/plugins/metadata-store-jcr/src/test/java/org/apache/archiva/metadata/repository/stats/JcrRepositoryStatisticsGatheringTest.java
+++ b/archiva-modules/plugins/metadata-store-jcr/src/test/java/org/apache/archiva/metadata/repository/stats/JcrRepositoryStatisticsGatheringTest.java
@@ -24,6 +24,7 @@ import org.apache.archiva.metadata.model.MetadataFacetFactory;
 import org.apache.archiva.metadata.repository.AbstractMetadataRepositoryTest;
 import org.apache.archiva.metadata.repository.DefaultMetadataResolver;
 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
+import org.apache.archiva.metadata.repository.MetadataService;
 import org.apache.archiva.metadata.repository.RepositorySession;
 import org.apache.archiva.metadata.repository.jcr.JcrMetadataRepository;
 import org.apache.archiva.metadata.repository.jcr.JcrRepositorySessionFactory;
@@ -54,6 +55,7 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Calendar;
 import java.util.Date;
+import java.util.List;
 import java.util.Map;
 import java.util.zip.GZIPInputStream;
 
@@ -91,12 +93,14 @@ public class JcrRepositoryStatisticsGatheringTest
             org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
         }
 
-        Map<String, MetadataFacetFactory> factories = AbstractMetadataRepositoryTest.createTestMetadataFacetFactories();
+        List<MetadataFacetFactory> factories = AbstractMetadataRepositoryTest.createTestMetadataFacetFactories();
 
+        MetadataService metadataService = new MetadataService( );
+        metadataService.setMetadataFacetFactories( factories );
 
         JcrRepositorySessionFactory jcrSessionFactory = new JcrRepositorySessionFactory();
         jcrSessionFactory.setMetadataResolver(new DefaultMetadataResolver());
-        jcrSessionFactory.setMetadataFacetFactories(factories);
+        jcrSessionFactory.setMetadataService(metadataService);
 
         jcrSessionFactory.open();
         sessionFactory = jcrSessionFactory;
diff --git a/archiva-modules/plugins/problem-reports/src/main/java/org/apache/archiva/reports/RepositoryProblemFacetFactory.java b/archiva-modules/plugins/problem-reports/src/main/java/org/apache/archiva/reports/RepositoryProblemFacetFactory.java
index e2ca9c5..44001b7 100644
--- a/archiva-modules/plugins/problem-reports/src/main/java/org/apache/archiva/reports/RepositoryProblemFacetFactory.java
+++ b/archiva-modules/plugins/problem-reports/src/main/java/org/apache/archiva/reports/RepositoryProblemFacetFactory.java
@@ -19,8 +19,7 @@ package org.apache.archiva.reports;
  * under the License.
  */
 
-import org.apache.archiva.metadata.model.MetadataFacet;
-import org.apache.archiva.metadata.model.MetadataFacetFactory;
+import org.apache.archiva.metadata.model.facets.AbstractMetadataFacetFactory;
 import org.apache.archiva.metadata.model.facets.RepositoryProblemFacet;
 import org.springframework.stereotype.Service;
 
@@ -29,16 +28,21 @@ import org.springframework.stereotype.Service;
  */
 @Service( "metadataFacetFactory#org.apache.archiva.reports" )
 public class RepositoryProblemFacetFactory
-    implements MetadataFacetFactory
+    extends AbstractMetadataFacetFactory<RepositoryProblemFacet>
 {
+    protected RepositoryProblemFacetFactory( )
+    {
+        super( RepositoryProblemFacet.class );
+    }
+
     @Override
-    public MetadataFacet createMetadataFacet()
+    public RepositoryProblemFacet createMetadataFacet()
     {
         return new RepositoryProblemFacet();
     }
 
     @Override
-    public MetadataFacet createMetadataFacet( String repositoryId, String name )
+    public RepositoryProblemFacet createMetadataFacet( String repositoryId, String name )
     {
         return new RepositoryProblemFacet();
     }
diff --git a/archiva-modules/plugins/repository-statistics/src/main/java/org/apache/archiva/metadata/repository/stats/RepositoryStatisticsFactory.java b/archiva-modules/plugins/repository-statistics/src/main/java/org/apache/archiva/metadata/repository/stats/RepositoryStatisticsFactory.java
index ceb9118..beae25d 100644
--- a/archiva-modules/plugins/repository-statistics/src/main/java/org/apache/archiva/metadata/repository/stats/RepositoryStatisticsFactory.java
+++ b/archiva-modules/plugins/repository-statistics/src/main/java/org/apache/archiva/metadata/repository/stats/RepositoryStatisticsFactory.java
@@ -19,9 +19,9 @@ package org.apache.archiva.metadata.repository.stats;
  * under the License.
  */
 
-import org.apache.archiva.metadata.model.MetadataFacet;
-import org.apache.archiva.metadata.model.MetadataFacetFactory;
+import org.apache.archiva.metadata.model.facets.AbstractMetadataFacetFactory;
 import org.apache.archiva.metadata.repository.stats.model.DefaultRepositoryStatistics;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
 import org.springframework.stereotype.Service;
 
 /**
@@ -29,16 +29,21 @@ import org.springframework.stereotype.Service;
  */
 @Service( "metadataFacetFactory#org.apache.archiva.metadata.repository.stats" )
 public class RepositoryStatisticsFactory
-    implements MetadataFacetFactory
+    extends AbstractMetadataFacetFactory<RepositoryStatistics>
 {
+    protected RepositoryStatisticsFactory( )
+    {
+        super( RepositoryStatistics.class );
+    }
+
     @Override
-    public MetadataFacet createMetadataFacet()
+    public RepositoryStatistics createMetadataFacet()
     {
         return new DefaultRepositoryStatistics();
     }
 
     @Override
-    public MetadataFacet createMetadataFacet( String repositoryId, String name )
+    public RepositoryStatistics createMetadataFacet( String repositoryId, String name )
     {
         return new DefaultRepositoryStatistics();
     }


[archiva] 02/02: Implementing new stream methods

Posted by ma...@apache.org.
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 d4ce38836d9f093d2024e26182f38fa3bc4890e2
Author: Martin Stockhammer <ma...@apache.org>
AuthorDate: Tue Aug 20 00:08:08 2019 +0200

    Implementing new stream methods
---
 .../NewArtifactsRssFeedProcessorTest.java          |   7 +-
 .../archiva/metadata/model/ArtifactMetadata.java   |   1 +
 .../repository/AbstractMetadataRepository.java     |  77 +++++++++++++--
 .../repository/AbstractMetadataRepositoryTest.java |  59 +++++++++++-
 .../cassandra/CassandraMetadataRepository.java     | 106 +++++++++++++++++++--
 .../CassandraRepositorySessionFactory.java         |  18 +---
 .../cassandra/CassandraMetadataRepositoryTest.java |   8 +-
 .../repository/file/FileMetadataRepository.java    |  85 +++++++++++++----
 .../file/FileRepositorySessionFactory.java         |  18 +---
 .../file/FileMetadataRepositoryTest.java           |   8 +-
 .../repository/jcr/JcrMetadataRepository.java      |  75 +++++++--------
 .../repository/jcr/OakRepositoryFactory.java       |  85 +++++------------
 .../archiva/metadata/repository/jcr/jcr-schema.cnd |   3 +-
 13 files changed, 379 insertions(+), 171 deletions(-)

diff --git a/archiva-modules/archiva-web/archiva-rss/src/test/java/org/apache/archiva/rss/processor/NewArtifactsRssFeedProcessorTest.java b/archiva-modules/archiva-web/archiva-rss/src/test/java/org/apache/archiva/rss/processor/NewArtifactsRssFeedProcessorTest.java
index 473d7aa..9f16007 100644
--- a/archiva-modules/archiva-web/archiva-rss/src/test/java/org/apache/archiva/rss/processor/NewArtifactsRssFeedProcessorTest.java
+++ b/archiva-modules/archiva-web/archiva-rss/src/test/java/org/apache/archiva/rss/processor/NewArtifactsRssFeedProcessorTest.java
@@ -23,7 +23,9 @@ import com.sun.syndication.feed.synd.SyndEntry;
 import com.sun.syndication.feed.synd.SyndFeed;
 import junit.framework.TestCase;
 import org.apache.archiva.metadata.model.ArtifactMetadata;
+import org.apache.archiva.metadata.model.MetadataFacet;
 import org.apache.archiva.metadata.repository.AbstractMetadataRepository;
+import org.apache.archiva.metadata.repository.MetadataRepositoryException;
 import org.apache.archiva.metadata.repository.RepositorySession;
 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
 import org.apache.archiva.rss.RssFeedGenerator;
@@ -34,6 +36,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.time.ZonedDateTime;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
@@ -41,6 +44,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.TimeZone;
+import java.util.stream.Stream;
 
 @RunWith (ArchivaBlockJUnit4ClassRunner.class)
 public class NewArtifactsRssFeedProcessorTest
@@ -155,6 +159,8 @@ public class NewArtifactsRssFeedProcessorTest
 
         private List<ArtifactMetadata> artifactsByDateRange;
 
+
+
         @Override
         public List<ArtifactMetadata> getArtifactsByDateRange( RepositorySession session, String repoId, Date from, Date to )
         {
@@ -164,7 +170,6 @@ public class NewArtifactsRssFeedProcessorTest
             return artifactsByDateRange;
         }
 
-
         public void setFrom( Date from )
         {
             this.from = from;
diff --git a/archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/ArtifactMetadata.java b/archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/ArtifactMetadata.java
index 4b3f4ba..c4da249 100644
--- a/archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/ArtifactMetadata.java
+++ b/archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/ArtifactMetadata.java
@@ -227,6 +227,7 @@ public class ArtifactMetadata
         {
             return false;
         }
+        // We allow some
         if ( fileLastModified != null
             ? !fileLastModified.equals( that.fileLastModified )
             : that.fileLastModified != null )
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 86fbde6..20040c4 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
@@ -21,18 +21,33 @@ package org.apache.archiva.metadata.repository;
 
 import org.apache.archiva.metadata.model.ArtifactMetadata;
 import org.apache.archiva.metadata.model.MetadataFacet;
+import org.apache.archiva.metadata.model.MetadataFacetFactory;
 import org.apache.archiva.metadata.model.ProjectMetadata;
 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
 import org.apache.archiva.metadata.model.ProjectVersionReference;
 
+import java.time.ZonedDateTime;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
 
 public abstract class AbstractMetadataRepository
     implements MetadataRepository
 {
 
+    protected MetadataService metadataService;
+
+    public AbstractMetadataRepository() {
+
+    }
+
+    public AbstractMetadataRepository( MetadataService metadataService )
+    {
+        this.metadataService = metadataService;
+    }
+
     @Override
     public void updateProject( RepositorySession session, String repositoryId, ProjectMetadata project )
         throws MetadataRepositoryException
@@ -78,13 +93,6 @@ public abstract class AbstractMetadataRepository
     }
 
     @Override
-    public MetadataFacet getMetadataFacet( RepositorySession session, String repositoryId, String facetId, String name )
-        throws MetadataRepositoryException
-    {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
     public void addMetadataFacet( RepositorySession session, String repositoryId, MetadataFacet metadataFacet )
         throws MetadataRepositoryException
     {
@@ -296,4 +304,59 @@ public abstract class AbstractMetadataRepository
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public <T extends MetadataFacet> Stream<T> getMetadataFacetStream( RepositorySession session, String repositoryId, Class<T> facetClazz ) throws MetadataRepositoryException
+    {
+        return getMetadataFacetStream( session, repositoryId, facetClazz, 0, Long.MAX_VALUE );
+    }
+
+    @Override
+    public Stream<ArtifactMetadata> getArtifactsByDateRangeStream( RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime ) throws MetadataRepositoryException
+    {
+        return getArtifactsByDateRangeStream( session, repositoryId, startTime, endTime, 0, Long.MAX_VALUE );
+    }
+
+    @Override
+    public MetadataFacet getMetadataFacet( RepositorySession session, String repositoryId, String facetId, String name )
+        throws MetadataRepositoryException
+    {
+        return getMetadataFacet( session, repositoryId, getFactoryClassForId( facetId ), name );
+    }
+
+    @Override
+    public <T extends MetadataFacet> Stream<T> getMetadataFacetStream( RepositorySession session, String repositoryId, Class<T> facetClazz, long offset, long maxEntries ) throws MetadataRepositoryException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T extends MetadataFacet> T getMetadataFacet( RepositorySession session, String repositoryId, Class<T> clazz, String name ) throws MetadataRepositoryException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+
+
+    @Override
+    public Stream<ArtifactMetadata> getArtifactsByDateRangeStream( RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime, long offset, long maxEntries ) throws MetadataRepositoryException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+
+    protected <T extends MetadataFacet> MetadataFacetFactory getFacetFactory(Class<T> facetClazz) {
+        return metadataService.getFactory( facetClazz );
+    }
+
+    protected MetadataFacetFactory getFacetFactory(String facetId) {
+        return metadataService.getFactory( facetId );
+    }
+
+    protected Set<String> getSupportedFacets() {
+        return metadataService.getSupportedFacets( );
+    }
+
+    protected Class<? extends MetadataFacet> getFactoryClassForId( String facetId ) {
+        return metadataService.getFactoryClassForId( facetId );
+    }
 }
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 ea47a00..3da98c9 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
@@ -156,7 +156,7 @@ public abstract class AbstractMetadataRepositoryTest
             @Override
             public TestMetadataFacet createMetadataFacet( String repositoryId, String name )
             {
-                return new TestMetadataFacet( TEST_METADATA_VALUE );
+                return new TestMetadataFacet( TEST_FACET_ID, TEST_METADATA_VALUE, name );
             }
 
             @Override
@@ -896,6 +896,34 @@ public abstract class AbstractMetadataRepositoryTest
     }
 
     @Test
+    public void testGetMetadataFacetsStreamWithLimit( )
+        throws Exception
+    {
+        try ( RepositorySession session = getSessionFactory( ).createSession( ) )
+        {
+            for (int i = 0; i<500; i++)
+            {
+                getRepository( ).addMetadataFacet( session, TEST_REPO_ID, new TestMetadataFacet( TEST_FACET_ID, TEST_VALUE, TEST_NAME+"/"+i ) );
+            }
+        }
+
+        try ( RepositorySession session = getSessionFactory( ).createSession( ) )
+        {
+            tryAssert( ( ) -> {
+                Stream<TestMetadataFacet> str = getRepository( ).getMetadataFacetStream( session, TEST_REPO_ID, TestMetadataFacet.class, 0, 100 );
+                assertNotNull( str );
+                List<TestMetadataFacet> result = str.collect( Collectors.toList( ) );
+                assertEquals( 100, result.size( ) );
+                for (int i=0; i<10; i++) {
+                    log.info( "Result {}", result.get( i ).getName( ) );
+                }
+                assertEquals( TEST_NAME+"/"+0, result.get( 0 ).getName( ) );
+            }, 2, 500 );
+
+        }
+    }
+
+    @Test
     public void testGetMetadataFacetsWhenEmpty( )
         throws Exception
     {
@@ -1320,8 +1348,11 @@ public abstract class AbstractMetadataRepositoryTest
             session.save( );
 
             // test it restricts to the appropriate repository
-            tryAssert( ( ) -> assertEquals( Collections.singletonList( artifact ), getRepository( ).getArtifacts( session, TEST_REPO_ID ) ) );
-            tryAssert( ( ) -> assertEquals( Collections.singletonList( secondArtifact ), getRepository( ).getArtifacts( session, OTHER_REPO_ID ) ) );
+            tryAssert( ( ) -> {
+                List<ArtifactMetadata> artifact1 = getRepository( ).getArtifacts( session, TEST_REPO_ID );
+                assertEquals( Collections.singletonList( artifact ), artifact1 );
+                assertEquals( Collections.singletonList( secondArtifact ), getRepository( ).getArtifacts( session, OTHER_REPO_ID ) );
+            });
 
         }
     }
@@ -2254,18 +2285,36 @@ public abstract class AbstractMetadataRepositoryTest
 
         private String value;
 
+        private String name = TEST_NAME;
+
         private TestMetadataFacet( String value )
         {
             this.value = value;
             testFacetId = TEST_FACET_ID;
         }
 
+
+
         private TestMetadataFacet( String facetId, String value )
         {
             this.value = value;
             testFacetId = facetId;
         }
 
+        private TestMetadataFacet( String facetId, String value, String name)
+        {
+            this.value = value;
+            testFacetId = facetId;
+            this.name = name;
+        }
+
+        private TestMetadataFacet( String facetId, String value, String name, Map<String, String> additionalProps )
+        {
+            this( facetId, value, name );
+            this.additionalProps = additionalProps;
+
+        }
+
         private TestMetadataFacet( String facetId, String value, Map<String, String> additionalProps )
         {
             this( facetId, value );
@@ -2281,7 +2330,7 @@ public abstract class AbstractMetadataRepositoryTest
         @Override
         public String getName( )
         {
-            return TEST_NAME;
+            return name;
         }
 
         @Override
@@ -2341,7 +2390,7 @@ public abstract class AbstractMetadataRepositoryTest
         @Override
         public String toString( )
         {
-            return "TestMetadataFacet{" + "value='" + value + '\'' + '}';
+            return "TestMetadataFacet{ name='"+ name+ "' value='" + value + '\'' + '}';
         }
 
         @Override
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 05d6c5c3..757d50a 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
@@ -52,9 +52,11 @@ import org.apache.archiva.metadata.model.ProjectMetadata;
 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
 import org.apache.archiva.metadata.model.ProjectVersionReference;
 import org.apache.archiva.metadata.model.Scm;
+import org.apache.archiva.metadata.repository.AbstractMetadataRepository;
 import org.apache.archiva.metadata.repository.MetadataRepository;
 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
 import org.apache.archiva.metadata.repository.MetadataResolutionException;
+import org.apache.archiva.metadata.repository.MetadataService;
 import org.apache.archiva.metadata.repository.RepositorySession;
 import org.apache.archiva.metadata.repository.cassandra.model.ArtifactMetadataModel;
 import org.apache.archiva.metadata.repository.cassandra.model.MetadataFacetModel;
@@ -62,11 +64,13 @@ import org.apache.archiva.metadata.repository.cassandra.model.Namespace;
 import org.apache.archiva.metadata.repository.cassandra.model.Project;
 import org.apache.archiva.metadata.repository.cassandra.model.ProjectVersionMetadataModel;
 import org.apache.archiva.metadata.repository.cassandra.model.Repository;
+import org.apache.archiva.repository.RepositoryException;
 import org.apache.commons.lang.StringUtils;
 import org.modelmapper.ModelMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.time.ZonedDateTime;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -78,7 +82,12 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.Spliterator;
 import java.util.UUID;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 import static org.apache.archiva.metadata.repository.cassandra.CassandraUtils.*;
 import static org.apache.archiva.metadata.repository.cassandra.model.ColumnNames.*;
@@ -88,15 +97,13 @@ import static org.apache.archiva.metadata.repository.cassandra.model.ColumnNames
  * @since 2.0.0
  */
 public class CassandraMetadataRepository
-    implements MetadataRepository
+    extends AbstractMetadataRepository implements MetadataRepository
 {
 
     private Logger logger = LoggerFactory.getLogger( getClass() );
 
     private ArchivaConfiguration configuration;
 
-    private final Map<String, MetadataFacetFactory> metadataFacetFactories;
-
     private final CassandraArchivaManager cassandraArchivaManager;
 
     private final ColumnFamilyTemplate<String, String> projectVersionMetadataTemplate;
@@ -117,11 +124,11 @@ public class CassandraMetadataRepository
 
     private final StringSerializer ss = StringSerializer.get();
 
-    public CassandraMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories,
+    public CassandraMetadataRepository( MetadataService metadataService,
                                         ArchivaConfiguration configuration,
                                         CassandraArchivaManager cassandraArchivaManager )
     {
-        this.metadataFacetFactories = metadataFacetFactories;
+        super( metadataService );
         this.configuration = configuration;
         this.cassandraArchivaManager = cassandraArchivaManager;
         this.keyspace = cassandraArchivaManager.getKeyspace();
@@ -1026,7 +1033,7 @@ public class CassandraMetadataRepository
         {
             for ( Map.Entry<String, Map<String, String>> entry : metadataFacetsPerFacetIds.entrySet() )
             {
-                MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( entry.getKey() );
+                MetadataFacetFactory metadataFacetFactory = getFacetFactory( entry.getKey() );
                 if ( metadataFacetFactory != null )
                 {
                     MetadataFacet metadataFacet = metadataFacetFactory.createMetadataFacet();
@@ -1445,7 +1452,7 @@ public class CassandraMetadataRepository
 
         String cf = cassandraArchivaManager.getMetadataFacetFamilyName();
 
-        for ( final String facetId : metadataFacetFactories.keySet() )
+        for ( final String facetId : getSupportedFacets() )
         {
             MetadataFacet metadataFacet = facetedMetadata.getFacet( facetId );
             if ( metadataFacet == null )
@@ -1518,6 +1525,75 @@ public class CassandraMetadataRepository
         return facets;
     }
 
+    private <T> Spliterator<T> createResultSpliterator( QueryResult<OrderedRows<String, String, String>> result, Function<Row<String, String, String>, T> converter) throws MetadataRepositoryException
+    {
+        final int size = result.get().getCount();
+        return new Spliterator<T>( )
+        {
+            @Override
+            public boolean tryAdvance( Consumer<? super T> action )
+            {
+                if (size>=1)
+                {
+                    for ( Row<String, String, String> row : result.get( ) )
+                    {
+                        T item = converter.apply( row );
+                        if ( item != null )
+                        {
+                            action.accept( item );
+                            return true;
+                        }
+                    }
+
+                }
+                return false;
+            }
+
+            @Override
+            public Spliterator<T> trySplit( )
+            {
+                return null;
+            }
+
+            @Override
+            public long estimateSize( )
+            {
+                return size;
+            }
+
+            @Override
+            public int characteristics( )
+            {
+                return ORDERED+NONNULL+SIZED;
+            }
+        };
+    }
+
+    @Override
+    public <T extends MetadataFacet> Stream<T> getMetadataFacetStream( RepositorySession session, String repositoryId, Class<T> facetClazz, long offset, long maxEntries ) throws MetadataRepositoryException
+    {
+        final MetadataFacetFactory<T> metadataFacetFactory = getFacetFactory( facetClazz );
+        final String facetId = metadataFacetFactory.getFacetId( );
+
+        QueryResult<OrderedRows<String, String, String>> result = HFactory //
+            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
+            .setColumnFamily( cassandraArchivaManager.getMetadataFacetFamilyName() ) //
+            .setColumnNames( NAME.toString() ) //
+            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
+            .addEqualsExpression( FACET_ID.toString(), facetId ) //
+            .execute();
+
+        return StreamSupport.stream( createResultSpliterator( result, ( Row<String, String, String> row)-> {
+            ColumnSlice<String, String> columnSlice = row.getColumnSlice();
+            String name = getStringValue( columnSlice, NAME.toString( ) );
+            T metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
+            Map<String, String> map = new HashMap<>( );
+            map.put( getStringValue( columnSlice, KEY.toString() ), getStringValue( columnSlice, VALUE.toString() ) );
+            metadataFacet.fromProperties( map );
+            return metadataFacet;
+        }), false );
+    }
+
     @Override
     public boolean hasMetadataFacet( RepositorySession session, String repositoryId, String facetId )
         throws MetadataRepositoryException
@@ -1530,7 +1606,7 @@ public class CassandraMetadataRepository
         throws MetadataRepositoryException
     {
 
-        MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
+        MetadataFacetFactory metadataFacetFactory = getFacetFactory( facetId );
         if ( metadataFacetFactory == null )
         {
             return null;
@@ -1562,6 +1638,12 @@ public class CassandraMetadataRepository
     }
 
     @Override
+    public <T extends MetadataFacet> T getMetadataFacet( RepositorySession session, String repositoryId, Class<T> clazz, String name ) throws MetadataRepositoryException
+    {
+        return null;
+    }
+
+    @Override
     public void addMetadataFacet( RepositorySession session, String repositoryId, MetadataFacet metadataFacet )
         throws MetadataRepositoryException
     {
@@ -1703,6 +1785,12 @@ public class CassandraMetadataRepository
         return artifactMetadatas;
     }
 
+    @Override
+    public Stream<ArtifactMetadata> getArtifactsByDateRangeStream( RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime, long offset, long maxEntries ) throws MetadataRepositoryException
+    {
+        return null;
+    }
+
 
     protected ArtifactMetadata mapArtifactMetadataLongColumnSlice( ColumnSlice<String, Long> columnSlice )
     {
@@ -2175,7 +2263,7 @@ public class CassandraMetadataRepository
 
             for ( Map.Entry<String, List<MetadataFacetModel>> entry : metadataFacetValuesPerFacetId.entrySet() )
             {
-                MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( entry.getKey() );
+                MetadataFacetFactory metadataFacetFactory = getFacetFactory( entry.getKey() );
                 if ( metadataFacetFactory != null )
                 {
                     List<MetadataFacetModel> facetModels = entry.getValue();
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraRepositorySessionFactory.java b/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraRepositorySessionFactory.java
index 6413fa9..63a3926 100644
--- a/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraRepositorySessionFactory.java
+++ b/archiva-modules/plugins/metadata-store-cassandra/src/main/java/org/apache/archiva/metadata/repository/cassandra/CassandraRepositorySessionFactory.java
@@ -24,6 +24,7 @@ import org.apache.archiva.metadata.model.MetadataFacetFactory;
 import org.apache.archiva.metadata.repository.AbstractRepositorySessionFactory;
 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
 import org.apache.archiva.metadata.repository.MetadataResolver;
+import org.apache.archiva.metadata.repository.MetadataService;
 import org.apache.archiva.metadata.repository.RepositorySession;
 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
 import org.apache.commons.lang.StringUtils;
@@ -44,8 +45,6 @@ public class CassandraRepositorySessionFactory extends AbstractRepositorySession
     implements RepositorySessionFactory
 {
 
-    private Map<String, MetadataFacetFactory> metadataFacetFactories;
-
     @Inject
     @Named(value = "archivaConfiguration#default")
     private ArchivaConfiguration configuration;
@@ -59,18 +58,11 @@ public class CassandraRepositorySessionFactory extends AbstractRepositorySession
     @Inject
     private CassandraArchivaManager cassandraArchivaManager;
 
+    @Inject
+    private MetadataService metadataService;
+
     public void initialize()
     {
-        Map<String, MetadataFacetFactory> tmpMetadataFacetFactories =
-            applicationContext.getBeansOfType( MetadataFacetFactory.class );
-        // olamy with spring the ID.toString() is now "metadataFacetFactory#hint"
-        // whereas was only hint with plexus so let remove  metadataFacetFactory#
-        metadataFacetFactories = new HashMap<>( tmpMetadataFacetFactories.size() );
-
-        for ( Map.Entry<String, MetadataFacetFactory> entry : tmpMetadataFacetFactories.entrySet() )
-        {
-            metadataFacetFactories.put( StringUtils.substringAfterLast( entry.getKey(), "#" ), entry.getValue() );
-        }
     }
 
     @Override
@@ -83,7 +75,7 @@ public class CassandraRepositorySessionFactory extends AbstractRepositorySession
     public RepositorySession createSession() throws MetadataRepositoryException
     {
         CassandraMetadataRepository metadataRepository =
-            new CassandraMetadataRepository( metadataFacetFactories, configuration, cassandraArchivaManager );
+            new CassandraMetadataRepository( metadataService, configuration, cassandraArchivaManager );
         return new RepositorySession( metadataRepository, metadataResolver );
     }
 
diff --git a/archiva-modules/plugins/metadata-store-cassandra/src/test/java/org/apache/archiva/metadata/repository/cassandra/CassandraMetadataRepositoryTest.java b/archiva-modules/plugins/metadata-store-cassandra/src/test/java/org/apache/archiva/metadata/repository/cassandra/CassandraMetadataRepositoryTest.java
index e7ba4ed..b395e36 100644
--- a/archiva-modules/plugins/metadata-store-cassandra/src/test/java/org/apache/archiva/metadata/repository/cassandra/CassandraMetadataRepositoryTest.java
+++ b/archiva-modules/plugins/metadata-store-cassandra/src/test/java/org/apache/archiva/metadata/repository/cassandra/CassandraMetadataRepositoryTest.java
@@ -22,6 +22,7 @@ package org.apache.archiva.metadata.repository.cassandra;
 import org.apache.archiva.metadata.model.MetadataFacetFactory;
 import org.apache.archiva.metadata.repository.AbstractMetadataRepositoryTest;
 import org.apache.archiva.metadata.repository.MetadataRepository;
+import org.apache.archiva.metadata.repository.MetadataService;
 import org.apache.archiva.metadata.repository.RepositorySession;
 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
 import org.apache.archiva.metadata.repository.cassandra.model.ProjectVersionMetadataModel;
@@ -36,6 +37,7 @@ import javax.inject.Named;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.List;
 import java.util.Map;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -85,9 +87,11 @@ public class CassandraMetadataRepositoryTest
             org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
         }
 
-        Map<String, MetadataFacetFactory> factories = createTestMetadataFacetFactories();
+        List<MetadataFacetFactory> factories = createTestMetadataFacetFactories();
+        MetadataService metadataService = new MetadataService( );
+        metadataService.setMetadataFacetFactories( factories );
 
-        this.cmr = new CassandraMetadataRepository( factories, null, cassandraArchivaManager );
+        this.cmr = new CassandraMetadataRepository( metadataService, null, cassandraArchivaManager );
 
         sessionFactoryControl = EasyMock.createControl( );
         sessionFactory = sessionFactoryControl.createMock( RepositorySessionFactory.class );
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 6359355..6cf7c35 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
@@ -34,9 +34,11 @@ import org.apache.archiva.metadata.model.ProjectMetadata;
 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
 import org.apache.archiva.metadata.model.ProjectVersionReference;
 import org.apache.archiva.metadata.model.Scm;
+import org.apache.archiva.metadata.repository.AbstractMetadataRepository;
 import org.apache.archiva.metadata.repository.MetadataRepository;
 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
 import org.apache.archiva.metadata.repository.MetadataResolutionException;
+import org.apache.archiva.metadata.repository.MetadataService;
 import org.apache.archiva.metadata.repository.RepositorySession;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -50,6 +52,7 @@ import java.nio.file.Files;
 import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.time.ZonedDateTime;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -68,9 +71,8 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 public class FileMetadataRepository
-    implements MetadataRepository
+    extends AbstractMetadataRepository implements MetadataRepository
 {
-    private final Map<String, MetadataFacetFactory> metadataFacetFactories;
 
     private final ArchivaConfiguration configuration;
 
@@ -84,25 +86,33 @@ public class FileMetadataRepository
 
     private static final String METADATA_KEY = "metadata";
 
-    public FileMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories,
+    private Map<String, Path> baseDirectory = new HashMap<>(  );
+
+    public FileMetadataRepository( MetadataService metadataService,
                                    ArchivaConfiguration configuration )
     {
-        this.metadataFacetFactories = metadataFacetFactories;
+        super( metadataService );
         this.configuration = configuration;
     }
 
     private Path getBaseDirectory(String repoId )
         throws IOException
     {
-        // TODO: should be configurable, like the index
-        ManagedRepositoryConfiguration managedRepositoryConfiguration =
-            configuration.getConfiguration().getManagedRepositoriesAsMap().get( repoId );
-        if ( managedRepositoryConfiguration == null )
+        if (!baseDirectory.containsKey( repoId ))
         {
-            return Files.createTempDirectory( repoId );
+            Path baseDir;
+            ManagedRepositoryConfiguration managedRepositoryConfiguration =
+                configuration.getConfiguration( ).getManagedRepositoriesAsMap( ).get( repoId );
+            if ( managedRepositoryConfiguration == null )
+            {
+                baseDir = Files.createTempDirectory( repoId );
+            } else
+            {
+                baseDir = Paths.get( managedRepositoryConfiguration.getLocation( ) );
+            }
+            baseDirectory.put(repoId, baseDir.resolve( ".archiva" ));
         }
-        String basedir = managedRepositoryConfiguration.getLocation();
-        return Paths.get( basedir, ".archiva" );
+        return baseDirectory.get(repoId);
     }
 
     private Path getDirectory( String repoId )
@@ -340,6 +350,30 @@ public class FileMetadataRepository
     }
 
     @Override
+    public <T extends MetadataFacet> Stream<T> getMetadataFacetStream( RepositorySession session, String repositoryId, Class<T> facetClazz, long offset, long maxEntries ) throws MetadataRepositoryException
+    {
+        final MetadataFacetFactory<T> metadataFacetFactory = getFacetFactory( facetClazz );
+        if (metadataFacetFactory==null) {
+            return null;
+        }
+        final String facetId = metadataFacetFactory.getFacetId( );
+        final String searchFile = METADATA_KEY + ".properties";
+        try
+        {
+            Path directory = getMetadataDirectory( repositoryId, facetId );
+            return Files.walk( directory, FileVisitOption.FOLLOW_LINKS ).filter( Files::isDirectory )
+                .filter( path -> Files.exists( path.resolve( searchFile ) ) )
+                .map(path -> directory.relativize(path).toString())
+                .sorted()
+                .skip( offset )
+                .limit(maxEntries)
+                .map(name -> getMetadataFacet( session, repositoryId, facetClazz, name ));
+        } catch (IOException e) {
+            throw new MetadataRepositoryException( e.getMessage( ), e );
+        }
+    }
+
+    @Override
     public boolean hasMetadataFacet( RepositorySession session, String repositoryId, String facetId )
         throws MetadataRepositoryException
     {
@@ -362,8 +396,14 @@ public class FileMetadataRepository
 
 
     @Override
-    public MetadataFacet getMetadataFacet( RepositorySession session, String repositoryId, String facetId, String name )
+    public <T extends MetadataFacet>  T getMetadataFacet( RepositorySession session, String repositoryId, Class<T> facetClazz, String name )
     {
+        final MetadataFacetFactory<T> metadataFacetFactory = getFacetFactory( facetClazz );
+        if (metadataFacetFactory==null) {
+            return null;
+        }
+        final String facetId = metadataFacetFactory.getFacetId( );
+
         Properties properties;
         try
         {
@@ -379,8 +419,7 @@ public class FileMetadataRepository
             log.error( "Could not read properties from {}, {}: {}", repositoryId, facetId, e.getMessage(), e );
             return null;
         }
-        MetadataFacet metadataFacet = null;
-        MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
+        T metadataFacet = null;
         if ( metadataFacetFactory != null )
         {
             metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
@@ -395,6 +434,8 @@ public class FileMetadataRepository
         return metadataFacet;
     }
 
+
+
     @Override
     public void addMetadataFacet( RepositorySession session, String repositoryId, MetadataFacet metadataFacet )
     {
@@ -467,6 +508,18 @@ public class FileMetadataRepository
         }
     }
 
+    @Override
+    public Stream<ArtifactMetadata> getArtifactsByDateRangeStream( RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime ) throws MetadataRepositoryException
+    {
+        return null;
+    }
+
+    @Override
+    public Stream<ArtifactMetadata> getArtifactsByDateRangeStream( RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime, long offset, long maxEntries ) throws MetadataRepositoryException
+    {
+        return null;
+    }
+
     private void getArtifactsByDateRange( RepositorySession session, List<ArtifactMetadata> artifacts, String repoId, String ns, Date startTime,
                                           Date endTime )
         throws MetadataRepositoryException
@@ -568,7 +621,7 @@ public class FileMetadataRepository
                             String propertyPrefix = "artifact:facet:" + id + ":";
                             for ( String facetId : value.split( "," ) )
                             {
-                                MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
+                                MetadataFacetFactory factory = getFacetFactory( facetId );
                                 if ( factory == null )
                                 {
                                     log.error( "Attempted to load unknown artifact metadata facet: {}", facetId );
@@ -1132,7 +1185,7 @@ public class FileMetadataRepository
                 {
                     for ( String facetId : facetIds.split( "," ) )
                     {
-                        MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
+                        MetadataFacetFactory factory = getFacetFactory( facetId );
                         if ( factory == null )
                         {
                             log.error( "Attempted to load unknown project version metadata facet: {}", facetId );
diff --git a/archiva-modules/plugins/metadata-store-file/src/main/java/org/apache/archiva/metadata/repository/file/FileRepositorySessionFactory.java b/archiva-modules/plugins/metadata-store-file/src/main/java/org/apache/archiva/metadata/repository/file/FileRepositorySessionFactory.java
index e61a845..82df7f3 100644
--- a/archiva-modules/plugins/metadata-store-file/src/main/java/org/apache/archiva/metadata/repository/file/FileRepositorySessionFactory.java
+++ b/archiva-modules/plugins/metadata-store-file/src/main/java/org/apache/archiva/metadata/repository/file/FileRepositorySessionFactory.java
@@ -25,6 +25,7 @@ import org.apache.archiva.metadata.repository.AbstractRepositorySessionFactory;
 import org.apache.archiva.metadata.repository.MetadataRepository;
 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
 import org.apache.archiva.metadata.repository.MetadataResolver;
+import org.apache.archiva.metadata.repository.MetadataService;
 import org.apache.archiva.metadata.repository.RepositorySession;
 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
 import org.apache.commons.lang.StringUtils;
@@ -43,8 +44,6 @@ import java.util.Map;
 public class FileRepositorySessionFactory extends AbstractRepositorySessionFactory
     implements RepositorySessionFactory
 {
-    private Map<String, MetadataFacetFactory> metadataFacetFactories;
-
     @Inject
     @Named( value = "archivaConfiguration#default" )
     private ArchivaConfiguration configuration;
@@ -55,20 +54,13 @@ public class FileRepositorySessionFactory extends AbstractRepositorySessionFacto
     @Inject
     private ApplicationContext applicationContext;
 
+    @Inject
+    private MetadataService metadataService;
+
     public void initialize()
     {
         Map<String, MetadataFacetFactory> tmpMetadataFacetFactories =
             applicationContext.getBeansOfType( MetadataFacetFactory.class );
-        // olamy with spring the "id" is now "metadataFacetFactory#hint"
-        // whereas was only hint with plexus so let remove  metadataFacetFactory#
-        metadataFacetFactories = new HashMap<>( tmpMetadataFacetFactories.size() );
-
-        for ( Map.Entry<String, MetadataFacetFactory> entry : tmpMetadataFacetFactories.entrySet() )
-        {
-            metadataFacetFactories.put( StringUtils.substringAfterLast( entry.getKey(), "#" ), entry.getValue() );
-        }
-
-
     }
 
     @Override
@@ -79,7 +71,7 @@ public class FileRepositorySessionFactory extends AbstractRepositorySessionFacto
     @Override
     public RepositorySession createSession() throws MetadataRepositoryException
     {
-        MetadataRepository metadataRepository = new FileMetadataRepository( metadataFacetFactories, configuration );
+        MetadataRepository metadataRepository = new FileMetadataRepository( metadataService, configuration );
 
         return new RepositorySession( metadataRepository, metadataResolver );
     }
diff --git a/archiva-modules/plugins/metadata-store-file/src/test/java/org/apache/archiva/metadata/repository/file/FileMetadataRepositoryTest.java b/archiva-modules/plugins/metadata-store-file/src/test/java/org/apache/archiva/metadata/repository/file/FileMetadataRepositoryTest.java
index 1795518..41497ac 100644
--- a/archiva-modules/plugins/metadata-store-file/src/test/java/org/apache/archiva/metadata/repository/file/FileMetadataRepositoryTest.java
+++ b/archiva-modules/plugins/metadata-store-file/src/test/java/org/apache/archiva/metadata/repository/file/FileMetadataRepositoryTest.java
@@ -25,6 +25,7 @@ import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
 import org.apache.archiva.metadata.model.MetadataFacetFactory;
 import org.apache.archiva.metadata.repository.AbstractMetadataRepositoryTest;
 import org.apache.archiva.metadata.repository.MetadataRepository;
+import org.apache.archiva.metadata.repository.MetadataService;
 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
 import org.junit.Before;
 import org.junit.Ignore;
@@ -32,6 +33,7 @@ import org.junit.Ignore;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.List;
 import java.util.Map;
 
 import static org.mockito.Mockito.mock;
@@ -69,9 +71,11 @@ public class FileMetadataRepositoryTest
             org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
         }
         ArchivaConfiguration config = createTestConfiguration( directory );
-        Map<String, MetadataFacetFactory> factories = createTestMetadataFacetFactories();
+        List<MetadataFacetFactory> factories = createTestMetadataFacetFactories();
+        MetadataService metadataService = new MetadataService( );
+        metadataService.setMetadataFacetFactories( factories );
 
-        this.repository = new FileMetadataRepository( factories, config );
+        this.repository = new FileMetadataRepository( metadataService, config );
     }
 
     @Override
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 4a2c8b0..0d8a164 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
@@ -35,10 +35,12 @@ import org.apache.archiva.metadata.model.ProjectVersionMetadata;
 import org.apache.archiva.metadata.model.ProjectVersionReference;
 import org.apache.archiva.metadata.model.Scm;
 import org.apache.archiva.metadata.model.maven2.MavenArtifactFacet;
+import org.apache.archiva.metadata.repository.AbstractMetadataRepository;
 import org.apache.archiva.metadata.repository.MetadataRepository;
 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
 import org.apache.archiva.metadata.repository.MetadataResolutionException;
 import org.apache.archiva.metadata.repository.MetadataService;
+import org.apache.archiva.metadata.repository.MetadataSessionException;
 import org.apache.archiva.metadata.repository.RepositorySession;
 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
 import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsProvider;
@@ -98,7 +100,7 @@ import static org.apache.archiva.metadata.repository.jcr.JcrConstants.*;
  * TODO revise reference storage
  */
 public class JcrMetadataRepository
-    implements MetadataRepository, RepositoryStatisticsProvider
+    extends AbstractMetadataRepository implements MetadataRepository, RepositoryStatisticsProvider
 {
 
 
@@ -120,8 +122,6 @@ public class JcrMetadataRepository
 
     private static final String QUERY_ARTIFACT_2 = "')";
 
-    private MetadataService metadataService;
-
     private Logger log = LoggerFactory.getLogger( JcrMetadataRepository.class );
 
     private Repository repository;
@@ -129,7 +129,7 @@ public class JcrMetadataRepository
     public JcrMetadataRepository( MetadataService metadataService, Repository repository )
         throws RepositoryException
     {
-        this.metadataService = metadataService;
+        super( metadataService );
         this.repository = repository;
     }
 
@@ -542,21 +542,22 @@ public class JcrMetadataRepository
     }
 
     @Override
-    public <T extends MetadataFacet> Stream<T> getMetadataFacetStream( RepositorySession session, String repositoryId, Class<T> facetClazz ) throws MetadataRepositoryException
+    public <T extends MetadataFacet> Stream<T> getMetadataFacetStream( RepositorySession session, String repositoryId, Class<T> facetClazz,
+        long offset, long maxEntries) throws MetadataRepositoryException
     {
         final Session jcrSession = getSession( session );
         final MetadataFacetFactory<T> factory = metadataService.getFactory( facetClazz );
         final String facetId = factory.getFacetId( );
-        final String facetPath = getFacetPath( repositoryId, facetId );
-        String q = "SELECT * FROM ["+FACET_NODE_TYPE+"] AS facet WHERE ISDESCENDANTNODE(facet, [/"+facetPath+"])";
+        final String facetPath = '/'+getFacetPath( repositoryId, facetId );
+        String q = "SELECT * FROM ["+FACET_NODE_TYPE+"] AS facet WHERE ISDESCENDANTNODE(facet, ["+facetPath+"]) ORDER BY [facet].[archiva:name]";
         Map<String, String> params = new HashMap<>( );
-        QueryResult result = runNativeJcrQuery( jcrSession, q, params );
+        QueryResult result = runNativeJcrQuery( jcrSession, q, params, offset, maxEntries );
         return StreamSupport.stream( createResultSpliterator( result, (Row row)-> {
             try
             {
                 Node node = row.getNode( "facet" );
-                String path = StringUtils.removeStart( node.getPath(), facetPath);
-                return createFacet( factory, node, repositoryId, path );
+                String facetName = node.getProperty( "archiva:name" ).getString();
+                return createFacet( factory, node, repositoryId, facetName );
             }
             catch ( RepositoryException e )
             {
@@ -566,12 +567,6 @@ public class JcrMetadataRepository
 
     }
 
-    @Override
-    public <T extends MetadataFacet> Stream<T> getMetadataFacetStream( RepositorySession session, String repositoryId, Class<T> facetClazz, long offset, long maxEntries ) throws MetadataRepositoryException
-    {
-        return null;
-    }
-
     private void recurse( List<String> facets, String prefix, Node node )
         throws RepositoryException
     {
@@ -599,14 +594,14 @@ public class JcrMetadataRepository
             return null;
         }
         final Session jcrSession = getSession( session );
-        final MetadataFacetFactory<T> factory = metadataService.getFactory( clazz );
+        final MetadataFacetFactory<T> factory = getFacetFactory( clazz );
         final String facetId = factory.getFacetId( );
         try
         {
             Node root = jcrSession.getRootNode();
             Node node = root.getNode( getFacetPath( repositoryId, facetId, name ) );
 
-            if ( metadataService.getSupportedFacets().size()==0)
+            if ( getSupportedFacets().size()==0)
             {
                 return null;
             }
@@ -646,13 +641,6 @@ public class JcrMetadataRepository
     }
 
     @Override
-    public MetadataFacet getMetadataFacet( RepositorySession session, String repositoryId, String facetId, String name )
-        throws MetadataRepositoryException
-    {
-        return getMetadataFacet( session, repositoryId, metadataService.getFactoryClassForId( facetId ), name );
-    }
-
-    @Override
     public void addMetadataFacet( RepositorySession session, String repositoryId, MetadataFacet metadataFacet )
         throws MetadataRepositoryException
     {
@@ -665,19 +653,21 @@ public class JcrMetadataRepository
             String id = metadataFacet.getFacetId();
             Node facetNode = JcrUtils.getOrAddNode( facets, id );
 
-            Node node = getOrAddNodeByPath( facetNode, metadataFacet.getName() );
-            if (!node.isNodeType( FACET_NODE_TYPE ))
+            Node facetInstance = getOrAddNodeByPath( facetNode, metadataFacet.getName() );
+            if (!facetInstance.isNodeType( FACET_NODE_TYPE ))
             {
-                node.addMixin( FACET_NODE_TYPE );
-                node.setProperty( "facetId", id );
+                facetInstance.addMixin( FACET_NODE_TYPE );
+                facetInstance.setProperty( "archiva:facetId", id );
+                facetInstance.setProperty( "archiva:name", metadataFacet.getName( ) );
             }
 
             for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
             {
-                node.setProperty( entry.getKey(), entry.getValue() );
+                facetInstance.setProperty( entry.getKey(), entry.getValue() );
             }
+            session.save();
         }
-        catch ( RepositoryException e )
+        catch ( RepositoryException | MetadataSessionException e )
         {
             throw new MetadataRepositoryException( e.getMessage(), e );
         }
@@ -695,7 +685,7 @@ public class JcrMetadataRepository
             if ( root.hasNode( path ) )
             {
                 Node node = root.getNode( path );
-                if ( node.isNodeType( org.apache.archiva.metadata.repository.jcr.JcrConstants.NAMESPACE_NODE_TYPE ) )
+                if ( node.isNodeType( NAMESPACE_NODE_TYPE ) )
                 {
                     node.remove();
                 }
@@ -802,12 +792,6 @@ public class JcrMetadataRepository
     }
 
     @Override
-    public Stream<ArtifactMetadata> getArtifactsByDateRangeStream( RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime ) throws MetadataRepositoryException
-    {
-        return null;
-    }
-
-    @Override
     public Stream<ArtifactMetadata> getArtifactsByDateRangeStream( RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime, long offset, long maxEntries ) throws MetadataRepositoryException
     {
         return null;
@@ -887,7 +871,12 @@ public class JcrMetadataRepository
         return artifacts;
     }
 
-    public QueryResult runNativeJcrQuery( final Session jcrSession, final String q, final Map<String, String> bindingParam)
+    public QueryResult runNativeJcrQuery( final Session jcrSession, final String q, final Map<String, String> bindingParam) throws MetadataRepositoryException
+    {
+        return runNativeJcrQuery( jcrSession, q, bindingParam, 0, Long.MAX_VALUE );
+    }
+
+    public QueryResult runNativeJcrQuery( final Session jcrSession, final String q, final Map<String, String> bindingParam, long offset, long maxEntries)
         throws MetadataRepositoryException
     {
         Map<String, String> bindings;
@@ -899,8 +888,10 @@ public class JcrMetadataRepository
 
         try
         {
-            log.debug( "Query: {}", q );
+            log.debug( "Query: offset={}, limit={}, query={}", offset, maxEntries, q );
             Query query = jcrSession.getWorkspace().getQueryManager().createQuery( q, Query.JCR_SQL2 );
+            query.setLimit( maxEntries );
+            query.setOffset( offset );
             ValueFactory valueFactory = jcrSession.getValueFactory();
             for ( Entry<String, String> entry : bindings.entrySet() )
             {
@@ -1350,7 +1341,7 @@ public class JcrMetadataRepository
 
         try
         {
-            return getNodeNames( getSession(session), path, org.apache.archiva.metadata.repository.jcr.JcrConstants.NAMESPACE_NODE_TYPE );
+            return getNodeNames( getSession(session), path, NAMESPACE_NODE_TYPE );
         }
         catch ( MetadataRepositoryException e )
         {
@@ -1823,7 +1814,7 @@ public class JcrMetadataRepository
         throws RepositoryException
     {
         Node repo = getOrAddRepositoryContentNode( jcrSession, repositoryId );
-        return getOrAddNodeByPath( repo, namespace.replace( '.', '/' ), org.apache.archiva.metadata.repository.jcr.JcrConstants.NAMESPACE_NODE_TYPE );
+        return getOrAddNodeByPath( repo, namespace.replace( '.', '/' ), NAMESPACE_NODE_TYPE );
     }
 
     private Node getOrAddProjectNode( Session jcrSession, String repositoryId, String namespace, String projectId )
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 e9982dc..56f17b4 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
@@ -77,6 +77,7 @@ import org.slf4j.LoggerFactory;
 
 import javax.annotation.Nonnull;
 import javax.jcr.Repository;
+import java.io.Closeable;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -467,7 +468,7 @@ public class OakRepositoryFactory
                         FACET_NODE_TYPE //
                     ), Type.STRINGS );
                     IndexDefinitionBuilder idxBuilder = new IndexDefinitionBuilder( lucene );
-                    idxBuilder.async( "async", "nrt" ).includedPaths( "/repositories" ).evaluatePathRestrictions();
+                    idxBuilder.async( "async", "nrt", "sync" ).includedPaths( "/repositories" ).evaluatePathRestrictions();
 
                     initBaseRule(idxBuilder.indexRule( REPOSITORY_NODE_TYPE ));
                     initBaseRule(idxBuilder.indexRule( NAMESPACE_NODE_TYPE ))
@@ -485,8 +486,12 @@ public class OakRepositoryFactory
                         .property( "whenGathered" ).type("Date").propertyIndex().analyzed().ordered()
                         .property("size").type("Long").propertyIndex().analyzed().ordered()
                         .property("version").propertyIndex().analyzed().ordered();
+
                     initRegexAll( idxBuilder.indexRule( FACET_NODE_TYPE ) )
-                        .property("facetId").propertyIndex().analyzed().ordered();
+                        .property("archiva:facetId").propertyIndex().analyzed().ordered()
+                        .property("archiva:name").propertyIndex().analyzed().ordered();
+
+
                     idxBuilder.indexRule( MIXIN_META_SCM )
                         .property( "scm.connection" ).propertyIndex()
                         .property( "scm.developerConnection" ).propertyIndex()
@@ -525,9 +530,6 @@ public class OakRepositoryFactory
                     log.info( "Index: {} repo-lucene: {}", lucene, lucene.getChildNode( "repo-lucene" ) );
                     log.info( "repo-lucene Properties: {}", lucene.getChildNode( "repo-lucene" ).getProperties( ) );
                 } else {
-
-                    NodeBuilder lucene = oakIdx.child( "repo-lucene" );
-                    lucene.setProperty( "reindex", true );
                     log.info( "No Index update" );
                 }
                 // IndexUtils.createIndexDefinition(  )
@@ -557,73 +559,36 @@ public class OakRepositoryFactory
         Repository r = jcr.createRepository();
         stopWatch.stop();
         log.info( "time to create jcr repository: {} ms", stopWatch.getTime() );
-//        try
-//        {
-//            Thread.currentThread().sleep( 1000 );
-//        }
-//        catch ( InterruptedException e )
-//        {
-//            log.error( e.getMessage(), e );
-//        }
+
         return r;
 
 
     }
 
-    public void close()
-    {
-        log.info( "Closing JCR RepositoryFactory" );
-        if ( fileStore != null )
-        {
-            fileStore.close();
-        }
-
-        if (backgroundObserver != null){
-            backgroundObserver.close();
-        }
-
-        if (externalIndexObserver != null){
-            externalIndexObserver.close();
-        }
-
-        if (indexProvider != null) {
-            indexProvider.close();
-            indexProvider = null;
-        }
-
-        if (documentQueue != null){
+    private void closeSilently( Closeable service) {
+        if (service!=null) {
             try
             {
-                documentQueue.close();
+                service.close();
             }
-            catch ( IOException e )
+            catch ( Throwable e )
             {
-                e.printStackTrace( );
-            }
-        }
-
-        if (nrtIndexFactory != null){
-            try
-            {
-                nrtIndexFactory.close();
-            }
-            catch ( IOException e )
-            {
-                e.printStackTrace( );
+                //
             }
         }
+    }
 
-        //Close the copier first i.e. before executorService
-        if (indexCopier != null){
-            try
-            {
-                indexCopier.close();
-            }
-            catch ( IOException e )
-            {
-                e.printStackTrace( );
-            }
-        }
+    public void close()
+    {
+        log.info( "Closing JCR RepositoryFactory" );
+        closeSilently( fileStore );
+        closeSilently( backgroundObserver );
+        closeSilently( externalIndexObserver );
+        closeSilently( indexProvider );
+        indexProvider = null;
+        closeSilently( documentQueue );
+        closeSilently( nrtIndexFactory );
+        closeSilently( indexCopier );
 
         if (executorService != null){
             executorService.shutdown();
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 9b56d3f..ce33089 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
@@ -106,4 +106,5 @@
  + * (archiva:facet) multiple
 
 [archiva:facet] > archiva:base mixin
- - facetId
\ No newline at end of file
+ - archiva:facetId
+ - archiva:name
\ No newline at end of file