From 6cf4073a9e73b6517c51dc22db75fd97d2523695 Mon Sep 17 00:00:00 2001 From: Martin Stockhammer Date: Sun, 18 Aug 2019 20:56:46 +0200 Subject: [PATCH] Changing facet factories. Adding stream methods to metadata repository. --- .../maven2/MavenArtifactFacetFactory.java | 12 +- .../maven2/MavenProjectFacetFactory.java | 12 +- .../metadata/model/MetadataFacetFactory.java | 14 +- .../facets/AbstractMetadataFacetFactory.java | 67 +++++ .../repository/MetadataRepository.java | 159 ++++++++++- .../metadata/repository/MetadataResolver.java | 8 + .../metadata/repository/MetadataService.java | 100 +++++++ .../AbstractMetadataRepositoryTest.java | 68 ++++- .../archiva/audit/AuditEventFactory.java | 24 +- .../generic/GenericMetadataFacetFactory.java | 13 +- .../repository/jcr/JcrMetadataRepository.java | 265 ++++++++++++------ .../jcr/JcrRepositorySessionFactory.java | 52 +--- .../repository/jcr/OakRepositoryFactory.java | 4 +- .../metadata/repository/jcr/jcr-schema.cnd | 3 +- .../jcr/JcrMetadataRepositoryTest.java | 15 +- .../JcrRepositoryStatisticsGatheringTest.java | 8 +- .../RepositoryProblemFacetFactory.java | 14 +- .../stats/RepositoryStatisticsFactory.java | 15 +- 18 files changed, 662 insertions(+), 191 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 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 e0c57ba76..29bd3f67c 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 { + 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 a7bd89a29..a3b68c666 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 { + 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 e0804edc1..ec35ad7ec 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 { - 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 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 000000000..725774e94 --- /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 + */ +public abstract class AbstractMetadataFacetFactory implements MetadataFacetFactory +{ + private final String facetId; + private final Class facetClazz; + + protected AbstractMetadataFacetFactory( Class facetClazz, String facetId) { + this.facetId = facetId; + this.facetClazz = facetClazz; + } + + protected AbstractMetadataFacetFactory(Class 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 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 5048353b5..c35d5f937 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: + * + * try(RepositorySession session = sessionFactory.createSession() { + * // do your stuff + * } + * + * + * 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: + *
    + *
  • Repository ID: The identifier of the repository, where the artifact resides
  • + *
  • Namespace: This is a hierarchical coordinate for locating the projects. E.g. this corresponds to the groupId in maven.
  • + *
  • Project ID: The project itself
  • + *
  • Version: Each project may have different versions.
  • + *
  • Artifact: Artifacts correspond to files / blob data. Each artifact has additional metadata, like name, version, modification time, ...
  • + *
+ * + * 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 {@link MetadataRepositoryException}. + * + * 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 {@link org.apache.archiva.metadata.model.MetadataFacetFactory} 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 getMetadataFacets( RepositorySession session, String repositoryId, String facetId ) throws MetadataRepositoryException; + Stream getMetadataFacetStream( RepositorySession session, String repositoryId, Class facetClazz) + throws MetadataRepositoryException; + + Stream getMetadataFacetStream( RepositorySession session, String repositoryId, Class 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 {@link org.apache.archiva.metadata.model.MetadataFacetFactory}. + * + * @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 The facet object + * @return The facet instance if it exists. + * @throws MetadataRepositoryException + */ + T getMetadataFacet(RepositorySession session, String repositoryId, Class clazz, String name) + throws MetadataRepositoryException; + void addMetadataFacet( RepositorySession session, String repositoryId, MetadataFacet metadataFacet ) throws MetadataRepositoryException; @@ -102,6 +228,13 @@ public interface MetadataRepository List getArtifactsByDateRange( RepositorySession session, String repositoryId, Date startTime, Date endTime ) throws MetadataRepositoryException; + Stream getArtifactsByDateRangeStream( RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime ) + throws MetadataRepositoryException; + + Stream getArtifactsByDateRangeStream( RepositorySession session, String repositoryId, + ZonedDateTime startTime, ZonedDateTime endTime, long offset, long maxEntries ) + throws MetadataRepositoryException; + Collection 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 4cd2cfd41..aae2cf079 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 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 000000000..21c4f04d9 --- /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 + */ + +@SuppressWarnings( "SpringJavaInjectionPointsAutowiringInspection" ) +@Service("metadataService") +public class MetadataService +{ + + private Map> facetFactories = new HashMap<>( ); + private Map, MetadataFacetFactory> facetFactoriesByClass = new HashMap<>( ); + private Map> reverseFactoryMap = new HashMap<>( ); + + private MetadataResolver metadataResolver = null; + + @Inject + ApplicationContext applicationContext; + + + @Inject + public void setMetadataFacetFactories( List factoryList ) { + Map> facetFactories = new HashMap<>( ); + Map, MetadataFacetFactory> facetFactoriesByClass = new HashMap<>( ); + Map> 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 MetadataFacetFactory getFactory(Class facetClazz) { + return (MetadataFacetFactory) facetFactoriesByClass.get( facetClazz ); + } + + public MetadataFacetFactory getFactory(String facetId) { + return facetFactories.get( facetId ); + } + + public Set getSupportedFacets() { + return facetFactories.keySet( ); + } + + public boolean supportsFacet(Class facetClazz) { + return facetFactoriesByClass.containsKey( facetClazz ); + } + + public boolean supportsFacet(String facetId) { + return facetFactories.containsKey( facetId ); + } + + public Class 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 a5574d635..ea47a00bf 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 createTestMetadataFacetFactories( ) + public static List createTestMetadataFacetFactories( ) { - Map factories = new HashMap<>( ); - factories.put( TEST_FACET_ID, new MetadataFacetFactory( ) + List factories = new ArrayList<>( ); + factories.add( new MetadataFacetFactory( ) { @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 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 @@ -793,6 +793,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 @@ -857,6 +873,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 str = getRepository( ).getMetadataFacetStream( session, TEST_REPO_ID, TestMetadataFacet.class ); + assertNotNull( str ); + List 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 620100fcf..c76be7e8c 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 { + 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 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 8d4dfb67a..b5aad19a9 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 { + 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 00cef0828..4a2c8b098 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 metadataFacetFactories; + private MetadataService metadataService; private Logger log = LoggerFactory.getLogger( JcrMetadataRepository.class ); private Repository repository; - public JcrMetadataRepository( Map 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 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 entry : facet.toProperties().entrySet() ) { @@ -513,6 +494,84 @@ public class JcrMetadataRepository return facets; } + private Spliterator createResultSpliterator(QueryResult result, Function converter) throws MetadataRepositoryException + { + final RowIterator rowIterator; + try + { + rowIterator = result.getRows(); + } + catch ( RepositoryException e ) + { + throw new MetadataRepositoryException( e.getMessage( ), e ); + } + return new Spliterator( ) + { + @Override + public boolean tryAdvance( Consumer action ) + { + while (rowIterator.hasNext()) { + T item = converter.apply( rowIterator.nextRow() ); + if (item!=null) + { + action.accept( item ); + return true; + } + } + return false; + } + + @Override + public Spliterator trySplit( ) + { + return null; + } + + @Override + public long estimateSize( ) + { + return 0; + } + + @Override + public int characteristics( ) + { + return ORDERED+NONNULL; + } + }; + } + + @Override + public Stream getMetadataFacetStream( RepositorySession session, String repositoryId, Class facetClazz ) throws MetadataRepositoryException + { + final Session jcrSession = getSession( session ); + final MetadataFacetFactory 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 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 Stream getMetadataFacetStream( RepositorySession session, String repositoryId, Class facetClazz, long offset, long maxEntries ) throws MetadataRepositoryException + { + return null; + } + private void recurse( List 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 getMetadataFacet( RepositorySession session, String repositoryId, Class 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 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 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 createFacet( MetadataFacetFactory factory, Node node, String repositoryId, String name ) throws RepositoryException + { + if ( factory != null ) + { + T metadataFacet = factory.createMetadataFacet( repositoryId, name ); + Map 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 entry : metadataFacet.toProperties().entrySet() ) { @@ -718,6 +801,18 @@ public class JcrMetadataRepository return artifacts; } + @Override + public Stream getArtifactsByDateRangeStream( RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime ) throws MetadataRepositoryException + { + return null; + } + + @Override + public Stream getArtifactsByDateRangeStream( RepositorySession session, String repositoryId, ZonedDateTime startTime, ZonedDateTime endTime, long offset, long maxEntries ) throws MetadataRepositoryException + { + return null; + } + @Override public List 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 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 f1f679822..0469b873b 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 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 cleanedMetadataFacetFactories = - new HashMap<>( metadataFacetFactories.size() ); - - for ( Map.Entry 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 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 677bf27d2..e9982dc52 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 e63d5fdc5..9b56d3fd5 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 171d6be60..58bb44188 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 factories = createTestMetadataFacetFactories( ); + List 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 6fe7da2b4..7e1e83da9 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 factories = AbstractMetadataRepositoryTest.createTestMetadataFacetFactories(); + List 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 e2ca9c579..44001b790 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 { + 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 ceb911803..beae25dee 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 { + 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(); } -- 2.39.5