]> source.dussan.org Git - archiva.git/commitdiff
[MRM-1957] Spliting statistics plugin module
authorMartin Stockhammer <martin_s@apache.org>
Sat, 15 Jul 2017 22:13:40 +0000 (00:13 +0200)
committerMartin Stockhammer <martin_s@apache.org>
Sun, 16 Jul 2017 15:56:54 +0000 (17:56 +0200)
Adding new API module (metadata-statistics-api) for statistics and move the
jcr specific tasks to the metadata store module.

Providing interfaces for the statistics API.

Removing dependencies to store specific libraries (like JCR) from the statistic
modules.

36 files changed:
archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/pom.xml
archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/managed/DefaultManagedRepositoryAdmin.java
archiva-modules/archiva-karaf/archiva-features/src/main/resources/features.xml
archiva-modules/archiva-scheduler/archiva-scheduler-repository-api/pom.xml
archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/main/java/org/apache/archiva/scheduler/repository/ArchivaRepositoryScanningTaskExecutor.java
archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/main/java/org/apache/archiva/scheduler/repository/DefaultRepositoryArchivaTaskScheduler.java
archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/java/org/apache/archiva/scheduler/repository/AbstractArchivaRepositoryScanningTaskExecutorTest.java
archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/java/org/apache/archiva/scheduler/repository/ArchivaRepositoryScanningTaskExecutorPhase2Test.java
archiva-modules/archiva-scheduler/archiva-scheduler-repository/src/test/java/org/apache/archiva/scheduler/repository/TestRepositoryStatisticsManager.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/ArchivaRepositoryStatistics.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/ReportRepositoriesService.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultManagedRepositoriesService.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultReportRepositoriesService.java
archiva-modules/archiva-web/archiva-webdav/pom.xml
archiva-modules/archiva-web/archiva-webdav/src/main/java/org/apache/archiva/webdav/ArchivaDavLocatorFactory.java
archiva-modules/metadata/metadata-repository-api/src/test/java/org/apache/archiva/metadata/repository/AbstractMetadataRepositoryTest.java
archiva-modules/metadata/metadata-statistics-api/pom.xml [new file with mode: 0644]
archiva-modules/metadata/metadata-statistics-api/src/main/java/org/apache/archiva/metadata/repository/stats/model/DefaultRepositoryStatistics.java [new file with mode: 0644]
archiva-modules/metadata/metadata-statistics-api/src/main/java/org/apache/archiva/metadata/repository/stats/model/RepositoryStatistics.java [new file with mode: 0644]
archiva-modules/metadata/metadata-statistics-api/src/main/java/org/apache/archiva/metadata/repository/stats/model/RepositoryStatisticsManager.java [new file with mode: 0644]
archiva-modules/metadata/metadata-statistics-api/src/main/java/org/apache/archiva/metadata/repository/stats/model/RepositoryStatisticsProvider.java [new file with mode: 0644]
archiva-modules/metadata/metadata-statistics-api/src/main/java/org/apache/archiva/metadata/repository/stats/model/RepositoryWalkingStatisticsProvider.java [new file with mode: 0644]
archiva-modules/metadata/metadata-statistics-api/src/test/java/org/apache/archiva/metadata/repository/stats/model/DefaultRepositoryStatisticsTest.java [new file with mode: 0644]
archiva-modules/metadata/pom.xml
archiva-modules/plugins/metadata-store-jcr/pom.xml
archiva-modules/plugins/metadata-store-jcr/src/main/java/org/apache/archiva/metadata/repository/jcr/JcrMetadataRepository.java
archiva-modules/plugins/metadata-store-jcr/src/test/java/org/apache/archiva/metadata/repository/stats/JcrRepositoryStatisticsGatheringTest.java [new file with mode: 0644]
archiva-modules/plugins/metadata-store-jcr/src/test/resources/artifacts.xml.gz [new file with mode: 0644]
archiva-modules/plugins/repository-statistics/pom.xml
archiva-modules/plugins/repository-statistics/src/main/java/org/apache/archiva/metadata/repository/stats/DefaultRepositoryStatisticsManager.java
archiva-modules/plugins/repository-statistics/src/main/java/org/apache/archiva/metadata/repository/stats/RepositoryStatistics.java [deleted file]
archiva-modules/plugins/repository-statistics/src/main/java/org/apache/archiva/metadata/repository/stats/RepositoryStatisticsFactory.java
archiva-modules/plugins/repository-statistics/src/main/java/org/apache/archiva/metadata/repository/stats/RepositoryStatisticsManager.java [deleted file]
archiva-modules/plugins/repository-statistics/src/test/java/org/apache/archiva/metadata/repository/stats/JcrRepositoryStatisticsGatheringTest.java [deleted file]
archiva-modules/plugins/repository-statistics/src/test/java/org/apache/archiva/metadata/repository/stats/RepositoryStatisticsManagerTest.java
pom.xml

index 06fe2e4dbe298e90556a61553e104e6b8550ec85..46e9ccfdb7105db51033883cdda00ddb4dfd72e4 100644 (file)
       <groupId>org.apache.archiva</groupId>
       <artifactId>metadata-repository-api</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>repository-statistics</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.apache.archiva</groupId>
       <artifactId>metadata-model</artifactId>
index f398bca26b8a24c514336b66bc94634606a9a33d..7975d1f461760882c2f6413f885c85eb19365dd8 100644 (file)
@@ -35,7 +35,7 @@ import org.apache.archiva.metadata.repository.MetadataRepository;
 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.metadata.repository.stats.RepositoryStatisticsManager;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsManager;
 import org.apache.archiva.redback.components.cache.Cache;
 import org.apache.archiva.redback.components.taskqueue.TaskQueueException;
 import org.apache.archiva.redback.role.RoleManager;
index 82d7cef403a3974aa0ac983b8d389be45c6fd3e1..dc5f9f75966e918b78296d26ac147eefec60558c 100644 (file)
@@ -89,6 +89,7 @@
     <feature version="[3,4)">spring</feature>
     <bundle>mvn:org.apache.archiva/metadata-model/${project.version}</bundle>
     <bundle>mvn:org.apache.archiva/metadata-repository-api/${project.version}</bundle>
+    <bundle>mvn:org.apache.archiva/metadata-statistics-api/${project.version}</bundle>
   </feature>
 
   <feature name="archiva-audit" description="Archiva Audit module" version="${project.version}" resolver="(obr)">
 
   <feature name="archiva-repository-statistics" description="Archiva Repository Statistics module" version="${project.version}" resolver="(obr)">
     <feature version="${project.version}">archiva-repository-layer</feature>
-    <bundle dependency="true">mvn:javax.jcr/jcr/${javax.jcr.version}</bundle>
-    <bundle dependency="true">mvn:org.apache.jackrabbit/jackrabbit-jcr-commons/${jackrabbit.version}</bundle>
     <bundle>mvn:org.apache.archiva/repository-statistics/${project.version}</bundle>
   </feature>
 
index 122542a6bfffc86bf88b19e1a142f0c18b40e7db..e728a8b30f4260d18dc7664aceaa15c4270e1ff9 100644 (file)
@@ -56,7 +56,7 @@
     </dependency>
     <dependency>
       <groupId>org.apache.archiva</groupId>
-      <artifactId>repository-statistics</artifactId>
+      <artifactId>metadata-statistics-api</artifactId>
     </dependency>
     <dependency>
       <groupId>org.apache.archiva</groupId>
index 3493168afd1d5a56005e2ef103aceefec8fd62d8..1ac363cd92d0f0a4d5145e63ce25b8c82c2008e6 100644 (file)
@@ -26,8 +26,8 @@ import org.apache.archiva.metadata.repository.MetadataRepository;
 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.metadata.repository.stats.RepositoryStatistics;
-import org.apache.archiva.metadata.repository.stats.RepositoryStatisticsManager;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsManager;
 import org.apache.archiva.repository.scanner.RepositoryContentConsumers;
 import org.apache.archiva.repository.scanner.RepositoryScanStatistics;
 import org.apache.archiva.repository.scanner.RepositoryScanner;
index 3012a40ec2cce02433ab4ffb38173e3d4ef973e9..672869b188e81145824681c9041c57d16b1add31 100644 (file)
@@ -28,7 +28,7 @@ import org.apache.archiva.metadata.repository.MetadataRepository;
 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.metadata.repository.stats.RepositoryStatisticsManager;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsManager;
 import org.apache.archiva.redback.components.scheduler.CronExpressionValidator;
 import org.apache.archiva.redback.components.scheduler.Scheduler;
 import org.apache.archiva.redback.components.taskqueue.TaskQueue;
index dcddb71538a6ea5b876e5944d64a7d6a2057d6a6..de7bd459d521c654f37eec32b0a0f676939175b1 100644 (file)
@@ -23,15 +23,13 @@ import junit.framework.TestCase;
 import org.apache.archiva.configuration.ArchivaConfiguration;
 import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
 import org.apache.archiva.metadata.repository.MetadataRepository;
-import org.apache.archiva.metadata.repository.stats.RepositoryStatisticsManager;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsManager;
 import org.apache.archiva.mock.MockRepositorySessionFactory;
 import org.apache.archiva.redback.components.taskqueue.execution.TaskExecutor;
 import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
-import org.apache.commons.lang.StringUtils;
 import org.codehaus.plexus.util.FileUtils;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.runner.RunWith;
 import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.ContextConfiguration;
@@ -40,7 +38,6 @@ import javax.inject.Inject;
 import javax.inject.Named;
 import java.io.File;
 import java.util.Calendar;
-import java.util.List;
 
 import static org.mockito.Mockito.mock;
 
index 6631339bb9c74bf5da29ba422757f870ed988ae6..885c9a6a8bc4dcf2f765bbe2cb1e4fa479007f94 100644 (file)
@@ -20,7 +20,8 @@ package org.apache.archiva.scheduler.repository;
  */
 
 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
-import org.apache.archiva.metadata.repository.stats.RepositoryStatistics;
+import org.apache.archiva.metadata.repository.stats.model.DefaultRepositoryStatistics;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
 import org.apache.archiva.model.ArtifactReference;
 import org.apache.archiva.scheduler.repository.model.RepositoryTask;
 import org.codehaus.plexus.util.FileUtils;
@@ -225,7 +226,7 @@ public class ArchivaRepositoryScanningTaskExecutorPhase2Test
         throws MetadataRepositoryException
     {
         Date date = Calendar.getInstance().getTime();
-        RepositoryStatistics stats = new RepositoryStatistics();
+        DefaultRepositoryStatistics stats = new DefaultRepositoryStatistics();
         stats.setScanStartTime( new Date( date.getTime() - 1234567 ) );
         stats.setScanEndTime( date );
         stats.setNewFileCount( 31 );
index d27e3506ff5d1ce98fa0ab5a50bf48ab57be685f..7f0512c84db088a2c70e257e7f5033fa2a115c71 100644 (file)
@@ -21,8 +21,9 @@ package org.apache.archiva.scheduler.repository;
 
 import org.apache.archiva.metadata.repository.MetadataRepository;
 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
-import org.apache.archiva.metadata.repository.stats.RepositoryStatistics;
-import org.apache.archiva.metadata.repository.stats.RepositoryStatisticsManager;
+import org.apache.archiva.metadata.repository.stats.model.DefaultRepositoryStatistics;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsManager;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
@@ -59,7 +60,7 @@ public class TestRepositoryStatisticsManager
     {
         List<RepositoryStatistics> stats = getStatsList( repositoryId );
 
-        RepositoryStatistics repositoryStatistics = new RepositoryStatistics();
+        DefaultRepositoryStatistics repositoryStatistics = new DefaultRepositoryStatistics();
         repositoryStatistics.setScanStartTime( startTime );
         repositoryStatistics.setScanEndTime( endTime );
         repositoryStatistics.setNewFileCount( newFiles );
index 8bf3ddccfacf88b1cf5e541653fadbae5646d85b..a1e5352cb76ed1d8f11df5fa0d5bc3ef5cf3c29a 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.archiva.rest.api.model;
 import javax.xml.bind.annotation.XmlRootElement;
 import java.io.Serializable;
 import java.util.Date;
+import java.util.Map;
 
 /**
  * @author Olivier Lamy
@@ -50,6 +51,10 @@ public class ArchivaRepositoryStatistics
 
     private String lastScanDate;
 
+    private Map<String, Long> totalCountForType;
+
+    private Map<String, Long> customValues;
+
     public ArchivaRepositoryStatistics()
     {
         // no op
@@ -155,6 +160,24 @@ public class ArchivaRepositoryStatistics
         this.lastScanDate = lastScanDate;
     }
 
+    public void setTotalCountForType(Map<String, Long> totalCountForType) {
+        this.totalCountForType = totalCountForType;
+    }
+
+    public Map<String, Long> getTotalCountForType() {
+        return this.totalCountForType;
+    }
+
+    public void setCustomValues(Map<String,Long> customValues) {
+        this.customValues = customValues;
+    }
+
+    public Map<String,Long> getCustomValues() {
+        return this.customValues;
+    }
+
+
+
     @Override
     public String toString()
     {
@@ -170,7 +193,16 @@ public class ArchivaRepositoryStatistics
         sb.append( ", newFileCount=" ).append( newFileCount );
         sb.append( ", duration=" ).append( duration );
         sb.append( ", lastScanDate='" ).append( lastScanDate ).append( '\'' );
+        addMapString( sb, totalCountForType );
+        addMapString( sb, customValues );
         sb.append( '}' );
         return sb.toString();
     }
+
+    private void addMapString(StringBuilder builder, Map<String, Long> map) {
+        if (map!=null)
+        {
+            map.entrySet( ).stream( ).forEach( entry -> builder.append( ", " ).append( entry.getKey( ) ).append( '=' ).append( entry.getValue( ) ) );
+        }
+    }
 }
index 1bb718554c99c92e6fed19bf277446dc835deddf..5f3eccf34f689a3b95c97ac2ea4dae176bf45a21 100644 (file)
@@ -19,7 +19,7 @@ package org.apache.archiva.rest.api.services;
  */
 
 import org.apache.archiva.metadata.model.facets.RepositoryProblemFacet;
-import org.apache.archiva.metadata.repository.stats.RepositoryStatistics;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
 import org.apache.archiva.redback.authorization.RedbackAuthorization;
 import org.apache.archiva.security.common.ArchivaRoleConstants;
 
index 9c10c9f09634372ecf79f6ef548b2a54ecb0c9c0..ed3ba676df27f6f08ba2520a751677cf6fb04108 100644 (file)
@@ -24,8 +24,8 @@ import org.apache.archiva.admin.model.beans.ManagedRepository;
 import org.apache.archiva.metadata.repository.MetadataRepository;
 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
 import org.apache.archiva.metadata.repository.RepositorySession;
-import org.apache.archiva.metadata.repository.stats.RepositoryStatistics;
-import org.apache.archiva.metadata.repository.stats.RepositoryStatisticsManager;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsManager;
 import org.apache.archiva.rest.api.model.ArchivaRepositoryStatistics;
 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
 import org.apache.archiva.rest.api.services.ManagedRepositoriesService;
index b8c1c74a56ecfe8d907d8b487914c4ec5726f146..b968e7a8517e2bdfbe922b3a9ecc29ff9d13c43c 100644 (file)
@@ -22,8 +22,9 @@ import org.apache.archiva.metadata.model.facets.RepositoryProblemFacet;
 import org.apache.archiva.metadata.repository.MetadataRepository;
 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
 import org.apache.archiva.metadata.repository.RepositorySession;
-import org.apache.archiva.metadata.repository.stats.RepositoryStatistics;
-import org.apache.archiva.metadata.repository.stats.RepositoryStatisticsManager;
+import org.apache.archiva.metadata.repository.stats.model.DefaultRepositoryStatistics;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsManager;
 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
 import org.apache.archiva.rest.api.services.ReportRepositoriesService;
 import org.apache.commons.lang.StringUtils;
index 2b08b3f297c8e9f433a6858662c2f18ea94c523d..33c8760110b5979fb3c4505a4fcabf41946dc95e 100644 (file)
         </exclusion>
       </exclusions>
     </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>jackrabbit-jcr-commons</artifactId>
+    </dependency>
     <dependency>
       <groupId>joda-time</groupId>
       <artifactId>joda-time</artifactId>
index 9d23b77332d3b6b62fae178b75279ddc6d016765..4bda0192464b91f6cf30a5f94c1defb18fd69feb 100644 (file)
@@ -19,10 +19,10 @@ package org.apache.archiva.webdav;
  * under the License.
  */
 
+import org.apache.archiva.webdav.util.RepositoryPathUtil;
 import org.apache.jackrabbit.util.Text;
 import org.apache.jackrabbit.webdav.DavLocatorFactory;
 import org.apache.jackrabbit.webdav.DavResourceLocator;
-import org.apache.archiva.webdav.util.RepositoryPathUtil;
 
 /**
  */
index 75c961fbc2e9dd797aec55fad5861f989f19a342..fef84df1baa5e0c5dfcbdeacce7cba0987a6194f 100644 (file)
@@ -101,7 +101,7 @@ public abstract class AbstractMetadataRepositoryTest
 
     protected Logger log = LoggerFactory.getLogger( getClass() );
 
-    protected static Map<String, MetadataFacetFactory> createTestMetadataFacetFactories()
+    public static Map<String, MetadataFacetFactory> createTestMetadataFacetFactories()
     {
         Map<String, MetadataFacetFactory> factories = new HashMap<>();
         factories.put( TEST_FACET_ID, new MetadataFacetFactory()
diff --git a/archiva-modules/metadata/metadata-statistics-api/pom.xml b/archiva-modules/metadata/metadata-statistics-api/pom.xml
new file mode 100644 (file)
index 0000000..251f2a7
--- /dev/null
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>metadata</artifactId>
+    <groupId>org.apache.archiva</groupId>
+    <version>3.0.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>metadata-statistics-api</artifactId>
+  <packaging>bundle</packaging>
+  <name>Archiva Metadata :: Statistics API</name>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>metadata-repository-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>metadata-model-maven2</artifactId>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <Bundle-SymbolicName>org.apache.archiva.metadata.repository.api</Bundle-SymbolicName>
+            <Bundle-Version>${project.version}</Bundle-Version>
+            <Export-Package>
+              org.apache.archiva.metadata.repository.stats.model;version=${project.version}
+            </Export-Package>
+            <Import-Package>
+              org.apache.archiva.metadata.model;version=${project.version},
+              org.apache.archiva.maven2.model;version=${project.version},
+              org.slf4j;resolution:=optional,
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/archiva-modules/metadata/metadata-statistics-api/src/main/java/org/apache/archiva/metadata/repository/stats/model/DefaultRepositoryStatistics.java b/archiva-modules/metadata/metadata-statistics-api/src/main/java/org/apache/archiva/metadata/repository/stats/model/DefaultRepositoryStatistics.java
new file mode 100644 (file)
index 0000000..0c88851
--- /dev/null
@@ -0,0 +1,412 @@
+package org.apache.archiva.metadata.repository.stats.model;
+
+/*
+ * 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 java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.stream.Collectors;
+
+/**
+ * Default statistics implementation
+ */
+public class DefaultRepositoryStatistics
+    implements RepositoryStatistics
+{
+    private Date scanEndTime;
+
+    private Date scanStartTime;
+
+    private long totalArtifactCount;
+
+    private long totalArtifactFileSize;
+
+    private long totalFileCount;
+
+    private long totalGroupCount;
+
+    private long totalProjectCount;
+
+    private long newFileCount;
+
+    public static final String SCAN_TIMESTAMP_FORMAT = "yyyy/MM/dd/HHmmss.SSS";
+
+    private Map<String, Long> totalCountForType = new ZeroForNullHashMap<>();
+
+    private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone( "UTC" );
+
+    private String repositoryId;
+
+    private Map<String, Long> customValues;
+
+    public static final String TYPE_PREFIX = "count-type-";
+    public static final String CUSTOM_PREFIX = "count-custom-";
+
+    @Override
+    public Date getScanEndTime( )
+    {
+        return scanEndTime;
+    }
+
+    public void setScanEndTime( Date scanEndTime )
+    {
+        this.scanEndTime = scanEndTime;
+    }
+
+    @Override
+    public Date getScanStartTime( )
+    {
+        return scanStartTime;
+    }
+
+    public void setScanStartTime( Date scanStartTime )
+    {
+        this.scanStartTime = scanStartTime;
+    }
+
+    @Override
+    public long getTotalArtifactCount( )
+    {
+        return totalArtifactCount;
+    }
+
+    @Override
+    public void setTotalArtifactCount( long totalArtifactCount )
+    {
+        this.totalArtifactCount = totalArtifactCount;
+    }
+
+    @Override
+    public long getTotalArtifactFileSize( )
+    {
+        return totalArtifactFileSize;
+    }
+
+    @Override
+    public void setTotalArtifactFileSize( long totalArtifactFileSize )
+    {
+        this.totalArtifactFileSize = totalArtifactFileSize;
+    }
+
+    @Override
+    public long getTotalFileCount( )
+    {
+        return totalFileCount;
+    }
+
+    @Override
+    public void setTotalFileCount( long totalFileCount )
+    {
+        this.totalFileCount = totalFileCount;
+    }
+
+    @Override
+    public long getTotalGroupCount( )
+    {
+        return totalGroupCount;
+    }
+
+    @Override
+    public void setTotalGroupCount( long totalGroupCount )
+    {
+        this.totalGroupCount = totalGroupCount;
+    }
+
+    @Override
+    public long getTotalProjectCount( )
+    {
+        return totalProjectCount;
+    }
+
+    @Override
+    public void setTotalProjectCount( long totalProjectCount )
+    {
+        this.totalProjectCount = totalProjectCount;
+    }
+
+    @Override
+    public void setNewFileCount( long newFileCount )
+    {
+        this.newFileCount = newFileCount;
+    }
+
+    @Override
+    public long getNewFileCount( )
+    {
+        return newFileCount;
+    }
+
+    @Override
+    public long getDuration( )
+    {
+        return scanEndTime.getTime() - scanStartTime.getTime();
+    }
+
+    @Override
+    public String getRepositoryId( )
+    {
+        return repositoryId;
+    }
+
+    public void setRepositoryId( String repositoryId )
+    {
+        this.repositoryId = repositoryId;
+    }
+
+    @Override
+    public String getFacetId()
+    {
+        return FACET_ID;
+    }
+
+    @Override
+    public String getName()
+    {
+        return createNameFormat().format( scanStartTime );
+    }
+
+    private static SimpleDateFormat createNameFormat()
+    {
+        SimpleDateFormat fmt = new SimpleDateFormat( SCAN_TIMESTAMP_FORMAT );
+        fmt.setTimeZone( UTC_TIME_ZONE );
+        return fmt;
+    }
+
+    @Override
+    public Map<String, String> toProperties()
+    {
+        Map<String, String> properties = new HashMap<>();
+        if (scanEndTime==null) {
+            properties.put("scanEndTime", "0");
+        } else
+        {
+            properties.put( "scanEndTime", String.valueOf( scanEndTime.getTime( ) ) );
+        }
+        if (scanStartTime==null) {
+            properties.put("scanStartTime","0");
+        } else
+        {
+            properties.put( "scanStartTime", String.valueOf( scanStartTime.getTime( ) ) );
+        }
+        properties.put( "totalArtifactCount", String.valueOf( totalArtifactCount ) );
+        properties.put( "totalArtifactFileSize", String.valueOf( totalArtifactFileSize ) );
+        properties.put( "totalFileCount", String.valueOf( totalFileCount ) );
+        properties.put( "totalGroupCount", String.valueOf( totalGroupCount ) );
+        properties.put( "totalProjectCount", String.valueOf( totalProjectCount ) );
+        properties.put( "newFileCount", String.valueOf( newFileCount ) );
+        properties.put( "repositoryId", repositoryId );
+        for ( Map.Entry<String, Long> entry : totalCountForType.entrySet() )
+        {
+            properties.put( TYPE_PREFIX + entry.getKey(), String.valueOf( entry.getValue() ) );
+        }
+        if (customValues!=null) {
+            for (Map.Entry<String, Long> entry : customValues.entrySet()) {
+                properties.put(CUSTOM_PREFIX+entry.getKey(), String.valueOf(entry.getValue()));
+            }
+        }
+        return properties;
+    }
+
+    @Override
+    public void fromProperties( Map<String, String> properties )
+    {
+        scanEndTime = new Date( Long.parseLong( properties.get( "scanEndTime" ) ) );
+        scanStartTime = new Date( Long.parseLong( properties.get( "scanStartTime" ) ) );
+        totalArtifactCount = Long.parseLong( properties.get( "totalArtifactCount" ) );
+        totalArtifactFileSize = Long.parseLong( properties.get( "totalArtifactFileSize" ) );
+        totalFileCount = Long.parseLong( properties.get( "totalFileCount" ) );
+        totalGroupCount = Long.parseLong( properties.get( "totalGroupCount" ) );
+        totalProjectCount = Long.parseLong( properties.get( "totalProjectCount" ) );
+        newFileCount = Long.parseLong( properties.get( "newFileCount" ) );
+        repositoryId = properties.get( "repositoryId" );
+        totalCountForType.clear();
+        for ( Map.Entry<String, String> entry : properties.entrySet() )
+        {
+            if ( entry.getKey().startsWith( TYPE_PREFIX ) )
+            {
+                totalCountForType.put( entry.getKey().substring( TYPE_PREFIX.length() ), Long.valueOf( entry.getValue() ) );
+            } else if (entry.getKey().startsWith( CUSTOM_PREFIX )) {
+                if (customValues==null) {
+                    createCustomValueMap();
+                }
+                customValues.put(entry.getKey().substring( CUSTOM_PREFIX.length() ), Long.valueOf(entry.getValue()));
+            }
+        }
+    }
+
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+        if ( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+
+        DefaultRepositoryStatistics that = (DefaultRepositoryStatistics) o;
+
+        if ( newFileCount != that.newFileCount )
+        {
+            return false;
+        }
+        if ( totalArtifactCount != that.totalArtifactCount )
+        {
+            return false;
+        }
+        if ( totalArtifactFileSize != that.totalArtifactFileSize )
+        {
+            return false;
+        }
+        if ( totalFileCount != that.totalFileCount )
+        {
+            return false;
+        }
+        if ( totalGroupCount != that.totalGroupCount )
+        {
+            return false;
+        }
+        if ( totalProjectCount != that.totalProjectCount )
+        {
+            return false;
+        }
+        if ( !scanEndTime.equals( that.scanEndTime ) )
+        {
+            return false;
+        }
+        if ( !scanStartTime.equals( that.scanStartTime ) )
+        {
+            return false;
+        }
+        if ( !totalCountForType.equals( that.totalCountForType ) )
+        {
+            return false;
+        }
+        if ( customValues==null && that.customValues!=null) {
+            return false;
+        }
+        if ( customValues!=null && that.customValues==null) {
+            return false;
+        }
+        if (customValues!=null && !customValues.equals(that.customValues)) {
+            return false;
+        }
+        return repositoryId.equals( that.repositoryId );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int result = scanEndTime.hashCode();
+        result = 31 * result + scanStartTime.hashCode();
+        result = 31 * result + (int) ( totalArtifactCount ^ ( totalArtifactCount >>> 32 ) );
+        result = 31 * result + (int) ( totalArtifactFileSize ^ ( totalArtifactFileSize >>> 32 ) );
+        result = 31 * result + (int) ( totalFileCount ^ ( totalFileCount >>> 32 ) );
+        result = 31 * result + (int) ( totalGroupCount ^ ( totalGroupCount >>> 32 ) );
+        result = 31 * result + (int) ( totalProjectCount ^ ( totalProjectCount >>> 32 ) );
+        result = 31 * result + (int) ( newFileCount ^ ( newFileCount >>> 32 ) );
+        result = 31 * result + totalCountForType.hashCode();
+        result = 31 * result + repositoryId.hashCode();
+        if (customValues!=null)
+            result = 31 * result + customValues.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "RepositoryStatistics{" + "scanEndTime=" + scanEndTime + ", scanStartTime=" + scanStartTime +
+            ", totalArtifactCount=" + totalArtifactCount + ", totalArtifactFileSize=" + totalArtifactFileSize +
+            ", totalFileCount=" + totalFileCount + ", totalGroupCount=" + totalGroupCount + ", totalProjectCount=" +
+            totalProjectCount + ", newFileCount=" + newFileCount + ", totalCountForType=" + totalCountForType + ", " +
+            "repositoryId=" + repositoryId +
+            getCustomValueString() +
+            '}';
+    }
+
+    private String getCustomValueString() {
+        if (customValues==null) {
+            return "";
+        } else {
+            return customValues.entrySet().stream().map(entry -> entry.getKey()+"="+entry.getValue()).collect(
+                Collectors.joining( ",")
+            );
+        }
+    }
+
+    @Override
+    public Map<String, Long> getTotalCountForType( )
+    {
+        return totalCountForType;
+    }
+
+    @Override
+    public long getTotalCountForType( String type )
+    {
+        return totalCountForType.get( type );
+    }
+
+    @Override
+    public void setTotalCountForType( String type, long count )
+    {
+        totalCountForType.put( type, count );
+    }
+
+    @Override
+    public long getCustomValue( String fieldName )
+    {
+        // Lazy evaluation, because it may not be used very often.
+        if (customValues==null) {
+            createCustomValueMap();
+        }
+        return customValues.get(fieldName);
+    }
+
+    @Override
+    public void setCustomValue( String fieldName, long count )
+    {
+        // Lazy evaluation, because it may not be used very often.
+        if (customValues==null) {
+            createCustomValueMap();
+        }
+        customValues.put(fieldName, count);
+    }
+
+    private void createCustomValueMap( )
+    {
+        customValues = new ZeroForNullHashMap<>();
+    }
+
+
+    private static final class ZeroForNullHashMap<K> extends HashMap<K, Long>
+    {   
+        @Override
+        public Long get(Object key) {
+            Long value = super.get( key );
+            
+            return ( value != null ) ? value : Long.valueOf( 0L );
+        }
+    }
+}
diff --git a/archiva-modules/metadata/metadata-statistics-api/src/main/java/org/apache/archiva/metadata/repository/stats/model/RepositoryStatistics.java b/archiva-modules/metadata/metadata-statistics-api/src/main/java/org/apache/archiva/metadata/repository/stats/model/RepositoryStatistics.java
new file mode 100644 (file)
index 0000000..e5fa94a
--- /dev/null
@@ -0,0 +1,109 @@
+package org.apache.archiva.metadata.repository.stats.model;
+
+/*
+ * 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 java.util.Date;
+import java.util.Map;
+
+/**
+ *
+ * Provides statistics data of metadata repositories.
+ *
+ * @since 2.3
+ */
+public interface RepositoryStatistics extends MetadataFacet
+{
+    String FACET_ID = "org.apache.archiva.metadata.repository.stats";
+
+    String getRepositoryId( );
+
+    Date getScanEndTime( );
+
+    Date getScanStartTime( );
+
+    long getTotalArtifactCount( );
+
+    void setTotalArtifactCount( long totalArtifactCount );
+
+    long getTotalArtifactFileSize( );
+
+    void setTotalArtifactFileSize( long totalArtifactFileSize );
+
+    long getTotalFileCount( );
+
+    void setTotalFileCount( long totalFileCount );
+
+    long getTotalGroupCount( );
+
+    void setTotalGroupCount( long totalGroupCount );
+
+    long getTotalProjectCount( );
+
+    void setTotalProjectCount( long totalProjectCount );
+
+    void setNewFileCount( long newFileCount );
+
+    long getNewFileCount( );
+
+    long getDuration( );
+
+    /**
+     * Statistics data by artifact type.
+     *
+     * @return A list of data keys and values
+     */
+    Map<String, Long> getTotalCountForType( );
+
+    /**
+     * Returns the value for the given artifact type.
+     *
+     * @param type The artifact type
+     * @return The count value.
+     */
+    long getTotalCountForType( String type );
+
+    /**
+     * Sets the value for the given artifact type.
+     * @param type The artifact type.
+     * @param count The count value.
+     */
+    void setTotalCountForType( String type, long count );
+
+    /**
+     * Reads custom statistic values that are store implementation
+     * specific.
+     *
+     * @param fieldName A unique field name.
+     */
+    long getCustomValue(String fieldName);
+
+    /**
+     * Saves custom statistic values that are store implementation
+     * specific. The field name should be unique (e.g. prefixed by the
+     * package name of the data provider).
+     *
+     * @param fieldName A unique field name.
+     * @param count The statistic counter value
+     */
+    void setCustomValue(String fieldName, long count);
+
+}
diff --git a/archiva-modules/metadata/metadata-statistics-api/src/main/java/org/apache/archiva/metadata/repository/stats/model/RepositoryStatisticsManager.java b/archiva-modules/metadata/metadata-statistics-api/src/main/java/org/apache/archiva/metadata/repository/stats/model/RepositoryStatisticsManager.java
new file mode 100644 (file)
index 0000000..f47e8cc
--- /dev/null
@@ -0,0 +1,52 @@
+package org.apache.archiva.metadata.repository.stats.model;
+
+/*
+ * 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.repository.MetadataRepository;
+import org.apache.archiva.metadata.repository.MetadataRepositoryException;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * The statistics manager is the central entry point for handling repository
+ * statistics data.
+ *
+ *
+ */
+public interface RepositoryStatisticsManager
+{
+    RepositoryStatistics getLastStatistics( MetadataRepository metadataRepository, String repositoryId )
+        throws MetadataRepositoryException;
+
+    boolean hasStatistics( MetadataRepository metadataRepository, String repositoryId )
+        throws MetadataRepositoryException;
+
+    void addStatisticsAfterScan( MetadataRepository metadataRepository, String repositoryId, Date startTime,
+                                 Date endTime, long totalFiles, long newFiles )
+        throws MetadataRepositoryException;
+
+    void deleteStatistics( MetadataRepository metadataRepository, String repositoryId )
+        throws MetadataRepositoryException;
+
+    List<RepositoryStatistics> getStatisticsInRange( MetadataRepository metadataRepository, String repositoryId,
+                                                     Date startTime, Date endTime )
+        throws MetadataRepositoryException;
+}
diff --git a/archiva-modules/metadata/metadata-statistics-api/src/main/java/org/apache/archiva/metadata/repository/stats/model/RepositoryStatisticsProvider.java b/archiva-modules/metadata/metadata-statistics-api/src/main/java/org/apache/archiva/metadata/repository/stats/model/RepositoryStatisticsProvider.java
new file mode 100644 (file)
index 0000000..112f86a
--- /dev/null
@@ -0,0 +1,47 @@
+package org.apache.archiva.metadata.repository.stats.model;
+
+/*
+ * 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.repository.MetadataRepository;
+import org.apache.archiva.metadata.repository.MetadataRepositoryException;
+
+/**
+ *
+ * This interface is used for populating statistics data. It should be implemented
+ * by metadata store implementations in the MetadataRepository class, if the store
+ * implementation can provide a faster implementation than walking the tree.
+ *
+ * @author Martin Stockhammer
+ * @since 2.3
+ */
+public interface RepositoryStatisticsProvider
+{
+
+    /**
+     * Populate the statistics object with the statistics data of this repository.
+     *
+     * @param repository The current metadata repository implementation
+     * @param repositoryId The repository Id
+     * @param statistics The statistics object that should be filled.
+     * @throws MetadataRepositoryException Is thrown, if an error occurs while accessing the repository
+     */
+    void populateStatistics( MetadataRepository repository, String repositoryId, RepositoryStatistics statistics)
+        throws MetadataRepositoryException;
+}
diff --git a/archiva-modules/metadata/metadata-statistics-api/src/main/java/org/apache/archiva/metadata/repository/stats/model/RepositoryWalkingStatisticsProvider.java b/archiva-modules/metadata/metadata-statistics-api/src/main/java/org/apache/archiva/metadata/repository/stats/model/RepositoryWalkingStatisticsProvider.java
new file mode 100644 (file)
index 0000000..9cc426c
--- /dev/null
@@ -0,0 +1,106 @@
+package org.apache.archiva.metadata.repository.stats.model;
+
+/*
+ * 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.ArtifactMetadata;
+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 java.util.Collection;
+
+/**
+ *
+ * This is a default implementation of a statistics provider that walks the tree and
+ * counts the artifacts found during the walk.
+ * The implementation is not very fast. If metadata store provider can improve the
+ * process by using store specific techniques (like query language) they should provide
+ * their own implementation.
+ *
+ * @author Martin Stockhammer
+ */
+public class RepositoryWalkingStatisticsProvider implements RepositoryStatisticsProvider
+{
+
+    /**
+     * Walks each namespace of the given repository id and counts the artifacts.
+     *
+     * @param metadataRepository The repository implementation
+     * @param repositoryId The repository Id
+     * @param repositoryStatistics The statistics object that must be populated
+     * @throws MetadataRepositoryException Throws the repository exception, if an error occurs while accessing the repository.
+     */
+    @Override
+    public void populateStatistics( MetadataRepository metadataRepository, String repositoryId,
+                                                       RepositoryStatistics repositoryStatistics )
+        throws MetadataRepositoryException
+    {
+        try
+        {
+            for ( String ns : metadataRepository.getRootNamespaces( repositoryId ) )
+            {
+                walkRepository( metadataRepository, repositoryStatistics, repositoryId, ns );
+            }
+        }
+        catch ( MetadataResolutionException e )
+        {
+            throw new MetadataRepositoryException( e.getMessage(), e );
+        }
+    }
+
+    private void walkRepository( MetadataRepository metadataRepository, RepositoryStatistics stats, String repositoryId,
+                                 String ns )
+        throws MetadataResolutionException
+    {
+        for ( String namespace : metadataRepository.getNamespaces( repositoryId, ns ) )
+        {
+            walkRepository( metadataRepository, stats, repositoryId, ns + "." + namespace );
+        }
+
+        Collection<String> projects = metadataRepository.getProjects( repositoryId, ns );
+        if ( !projects.isEmpty() )
+        {
+            stats.setTotalGroupCount( stats.getTotalGroupCount() + 1 );
+            stats.setTotalProjectCount( stats.getTotalProjectCount() + projects.size() );
+
+            for ( String project : projects )
+            {
+                for ( String version : metadataRepository.getProjectVersions( repositoryId, ns, project ) )
+                {
+                    for ( ArtifactMetadata artifact : metadataRepository.getArtifacts( repositoryId, ns, project,
+                        version ) )
+                    {
+                        stats.setTotalArtifactCount( stats.getTotalArtifactCount() + 1 );
+                        stats.setTotalArtifactFileSize( stats.getTotalArtifactFileSize() + artifact.getSize() );
+
+                        MavenArtifactFacet facet =
+                            (MavenArtifactFacet) artifact.getFacet( MavenArtifactFacet.FACET_ID );
+                        if ( facet != null )
+                        {
+                            String type = facet.getType();
+                            stats.setTotalCountForType( type, stats.getTotalCountForType( type ) + 1 );
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/archiva-modules/metadata/metadata-statistics-api/src/test/java/org/apache/archiva/metadata/repository/stats/model/DefaultRepositoryStatisticsTest.java b/archiva-modules/metadata/metadata-statistics-api/src/test/java/org/apache/archiva/metadata/repository/stats/model/DefaultRepositoryStatisticsTest.java
new file mode 100644 (file)
index 0000000..eb38a39
--- /dev/null
@@ -0,0 +1,109 @@
+package org.apache.archiva.metadata.repository.stats.model;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.junit.Test;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author Martin Stockhammer <martin_s@apache.org>
+ */
+public class DefaultRepositoryStatisticsTest
+{
+    @Test
+    public void toProperties( ) throws Exception
+    {
+        DefaultRepositoryStatistics stats = new DefaultRepositoryStatistics();
+        Date startTime = new Date();
+        Date endTime = new Date();
+        stats.setScanStartTime( startTime );
+        stats.setScanEndTime( endTime );
+        stats.setTotalFileCount( 500 );
+        stats.setNewFileCount( 10 );
+        stats.setRepositoryId( "test-repo" );
+        stats.setTotalArtifactCount( 300 );
+        stats.setTotalArtifactFileSize( 4848484 );
+        stats.setTotalGroupCount( 4 );
+        stats.setTotalProjectCount( 6 );
+        stats.setCustomValue( "test.value.1", 55 );
+        stats.setCustomValue( "test.value.2", 44);
+        stats.setTotalCountForType( "java-source",13 );
+        stats.setTotalCountForType( "pom", 5 );
+
+        Map<String, String> props = stats.toProperties( );
+
+        assertEquals( "500", props.get("totalFileCount") );
+        assertEquals( "10", props.get("newFileCount"));
+        assertEquals( "300", props.get("totalArtifactCount"));
+        assertEquals( "4848484", props.get("totalArtifactFileSize"));
+        assertEquals("4", props.get("totalGroupCount"));
+        assertEquals("6", props.get("totalProjectCount"));
+        assertEquals("55",props.get("count-custom-test.value.1" ));
+        assertEquals("44", props.get("count-custom-test.value.2"));
+        assertEquals("13", props.get("count-type-java-source"));
+        assertEquals("5", props.get("count-type-pom"));
+        assertEquals( String.valueOf(startTime.getTime()), props.get("scanStartTime"));
+        assertEquals( String.valueOf(endTime.getTime()), props.get("scanEndTime"));
+    }
+
+    @Test
+    public void fromProperties( ) throws Exception
+    {
+        DefaultRepositoryStatistics stats = new DefaultRepositoryStatistics( );
+        Date startTime = new Date();
+        Date endTime = new Date();
+        Map<String,String> props = new HashMap<>(  );
+        props.put("totalFileCount","501");
+        props.put("newFileCount","11");
+        props.put("totalArtifactCount","301");
+        props.put("totalArtifactFileSize","473565557");
+        props.put("totalGroupCount","5");
+        props.put("totalProjectCount","7");
+        props.put("count-custom-test.value.1","56");
+        props.put("count-custom-test.value.2","45");
+        props.put("count-type-java-source","14");
+        props.put("count-type-pom","6");
+        props.put("scanStartTime", String.valueOf(startTime.getTime()));
+        props.put("scanEndTime", String.valueOf(endTime.getTime()));
+
+        stats.fromProperties( props );
+
+        assertEquals(501,stats.getTotalFileCount());
+        assertEquals(11,stats.getNewFileCount());
+        assertEquals(301, stats.getTotalArtifactCount());
+        assertEquals(473565557, stats.getTotalArtifactFileSize());
+        assertEquals(5, stats.getTotalGroupCount());
+        assertEquals(7, stats.getTotalProjectCount());
+        assertEquals(56, stats.getCustomValue( "test.value.1" ));
+        assertEquals(45, stats.getCustomValue( "test.value.2" ));
+        assertEquals(14, stats.getTotalCountForType( "java-source" ));
+        assertEquals(6, stats.getTotalCountForType( "pom" ));
+        assertEquals(startTime, stats.getScanStartTime());
+        assertEquals( endTime, stats.getScanEndTime() );
+    }
+
+
+
+}
\ No newline at end of file
index 5ce399dea6cb1eb415086f6be32b4cc584719be7..1c1ba69786960882edcdf12ad58edc88137f21f8 100644 (file)
@@ -31,6 +31,7 @@
     <module>metadata-model</module>
     <module>metadata-repository-api</module>
     <module>metadata-model-maven2</module>
+    <module>metadata-statistics-api</module>
     <module>test-repository</module>
   </modules>
 </project>
\ No newline at end of file
index 8fa30860c462a7e8b8d191acbb523bf5d1ed132a..8e71c4c89da218eb5b56140a0cc38c4a613be8be 100644 (file)
       <groupId>org.apache.archiva</groupId>
       <artifactId>metadata-repository-api</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>metadata-statistics-api</artifactId>
+    </dependency>
     <dependency>
       <groupId>commons-lang</groupId>
       <artifactId>commons-lang</artifactId>
         <directory>src/test/filtered-resources</directory>
         <filtering>true</filtering>
       </testResource>
+      <testResource>
+        <directory>src/test/resources</directory>
+        <filtering>false</filtering>
+      </testResource>
     </testResources>
     <plugins>
       <plugin>
index 36493099857059f6dbd15f44bc1dd67f536906ea..2b76db4aff83c1c6c932c6d9d47e5f319b02e67a 100644 (file)
@@ -32,9 +32,12 @@ 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.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.stats.model.RepositoryStatistics;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsProvider;
 import org.apache.commons.lang.StringUtils;
 import org.apache.jackrabbit.commons.JcrUtils;
 import org.slf4j.Logger;
@@ -57,6 +60,7 @@ 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;
 import javax.jcr.query.Row;
 import javax.jcr.query.RowIterator;
@@ -80,7 +84,7 @@ import java.util.Set;
  * TODO revise reference storage
  */
 public class JcrMetadataRepository
-    implements MetadataRepository
+    implements MetadataRepository,RepositoryStatisticsProvider
 {
 
     private static final String JCR_LAST_MODIFIED = "jcr:lastModified";
@@ -113,7 +117,7 @@ public class JcrMetadataRepository
     }
 
 
-    static void initialize( Session session )
+    public static void initialize( Session session )
         throws RepositoryException
     {
 
@@ -1694,4 +1698,81 @@ public class JcrMetadataRepository
         }
         return this.jcrSession;
     }
+
+    @Override
+    public void populateStatistics( MetadataRepository repository, String repositoryId,
+                                            RepositoryStatistics repositoryStatistics )
+        throws MetadataRepositoryException
+    {
+        if (!(repository instanceof JcrMetadataRepository)) {
+            throw new MetadataRepositoryException( "The statistics population is only possible for JcrMetdataRepository implementations" );
+        }
+        Session session = (Session) repository.obtainAccess( Session.class );
+        // TODO: these may be best as running totals, maintained by observations on the properties in JCR
+
+        try
+        {
+            QueryManager queryManager = session.getWorkspace().getQueryManager();
+
+            // TODO: JCR-SQL2 query will not complete on a large repo in Jackrabbit 2.2.0 - see JCR-2835
+            //    Using the JCR-SQL2 variants gives
+            //      "org.apache.lucene.search.BooleanQuery$TooManyClauses: maxClauseCount is set to 1024"
+//            String whereClause = "WHERE ISDESCENDANTNODE([/repositories/" + repositoryId + "/content])";
+//            Query query = queryManager.createQuery( "SELECT size FROM [archiva:artifact] " + whereClause,
+//                                                    Query.JCR_SQL2 );
+            String whereClause = "WHERE jcr:path LIKE '/repositories/" + repositoryId + "/content/%'";
+            Query query = queryManager.createQuery( "SELECT size FROM archiva:artifact " + whereClause, Query.SQL );
+
+            QueryResult queryResult = query.execute();
+
+            Map<String, Integer> totalByType = new HashMap<>();
+            long totalSize = 0, totalArtifacts = 0;
+            for ( Row row : JcrUtils.getRows( queryResult ) )
+            {
+                Node n = row.getNode();
+                totalSize += row.getValue( "size" ).getLong();
+
+                String type;
+                if ( n.hasNode( MavenArtifactFacet.FACET_ID ) )
+                {
+                    Node facetNode = n.getNode( MavenArtifactFacet.FACET_ID );
+                    type = facetNode.getProperty( "type" ).getString();
+                }
+                else
+                {
+                    type = "Other";
+                }
+                Integer prev = totalByType.get( type );
+                totalByType.put( type, prev != null ? prev + 1 : 1 );
+
+                totalArtifacts++;
+            }
+
+            repositoryStatistics.setTotalArtifactCount( totalArtifacts );
+            repositoryStatistics.setTotalArtifactFileSize( totalSize );
+            for ( Map.Entry<String, Integer> entry : totalByType.entrySet() )
+            {
+                System.out.println("Setting count for type: "+entry.getKey()+" = "+entry.getValue());
+                repositoryStatistics.setTotalCountForType( entry.getKey(), entry.getValue() );
+            }
+
+            // The query ordering is a trick to ensure that the size is correct, otherwise due to lazy init it will be -1
+//            query = queryManager.createQuery( "SELECT * FROM [archiva:project] " + whereClause, Query.JCR_SQL2 );
+            query = queryManager.createQuery( "SELECT * FROM archiva:project " + whereClause + " ORDER BY jcr:score",
+                Query.SQL );
+            repositoryStatistics.setTotalProjectCount( query.execute().getRows().getSize() );
+
+//            query = queryManager.createQuery(
+//                "SELECT * FROM [archiva:namespace] " + whereClause + " AND namespace IS NOT NULL", Query.JCR_SQL2 );
+            query = queryManager.createQuery(
+                "SELECT * FROM archiva:namespace " + whereClause + " AND namespace IS NOT NULL ORDER BY jcr:score",
+                Query.SQL );
+            repositoryStatistics.setTotalGroupCount( query.execute().getRows().getSize() );
+        }
+        catch ( RepositoryException e )
+        {
+            throw new MetadataRepositoryException( e.getMessage(), e );
+        }
+    }
+
 }
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
new file mode 100644 (file)
index 0000000..63bfffb
--- /dev/null
@@ -0,0 +1,220 @@
+package org.apache.archiva.metadata.repository.stats;
+
+/*
+ * 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 junit.framework.TestCase;
+import org.apache.archiva.metadata.model.MetadataFacetFactory;
+import org.apache.archiva.metadata.repository.AbstractMetadataRepositoryTest;
+import org.apache.archiva.metadata.repository.RepositorySessionFactory;
+import org.apache.archiva.metadata.repository.jcr.JcrMetadataRepository;
+import org.apache.archiva.metadata.repository.stats.model.DefaultRepositoryStatistics;
+import org.apache.archiva.test.utils.ArchivaBlockJUnit4ClassRunner;
+import org.apache.archiva.test.utils.ArchivaSpringJUnit4ClassRunner;
+import org.apache.commons.io.FileUtils;
+import org.apache.jackrabbit.commons.JcrUtils;
+import org.apache.jackrabbit.core.TransientRepository;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.apache.regexp.RE;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.context.ApplicationContext;
+import org.springframework.test.context.ContextConfiguration;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.Workspace;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.NodeTypeTemplate;
+import java.io.File;
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Map;
+import java.util.zip.GZIPInputStream;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith( ArchivaSpringJUnit4ClassRunner.class )
+@ContextConfiguration( locations = { "classpath*:/META-INF/spring-context.xml", "classpath*:/spring-context.xml" } )
+public class JcrRepositoryStatisticsGatheringTest extends TestCase
+
+{
+    private static final int TOTAL_FILE_COUNT = 1000;
+
+    private static final int NEW_FILE_COUNT = 500;
+
+    private static final String TEST_REPO = "test-repo";
+
+    JcrMetadataRepository repository;
+
+    @Inject
+    private RepositorySessionFactory repositorySessionFactory;
+
+    @Inject
+    private ApplicationContext applicationContext;
+
+    @Inject
+    @Named("repository")
+    Repository jcrRepository;
+
+    Session session;
+
+
+
+
+    @Before
+    public void setUp()
+        throws Exception
+    {
+
+        File directory = new File( "target/test-repositories" );
+        if ( directory.exists() )
+        {
+            FileUtils.deleteDirectory( directory );
+        }
+
+        Map<String, MetadataFacetFactory> factories = AbstractMetadataRepositoryTest.createTestMetadataFacetFactories();
+
+        assertNotNull( jcrRepository );
+        // TODO: probably don't need to use Spring for this
+        JcrMetadataRepository jcrMetadataRepository = new JcrMetadataRepository( factories, jcrRepository );
+
+        try
+        {
+            session = jcrMetadataRepository.getJcrSession();
+
+            // set up namespaces, etc.
+            JcrMetadataRepository.initialize( session );
+
+            // removing content is faster than deleting and re-copying the files from target/jcr
+            session.getRootNode().getNode( "repositories" ).remove();
+        }
+        catch ( RepositoryException e )
+        {
+            // ignore
+        }
+
+        this.repository = jcrMetadataRepository;
+    }
+
+    private static void registerMixinNodeType( NodeTypeManager nodeTypeManager, String type )
+        throws RepositoryException
+    {
+        NodeTypeTemplate nodeType = nodeTypeManager.createNodeTypeTemplate();
+        nodeType.setMixin( true );
+        nodeType.setName( type );
+        nodeTypeManager.registerNodeType( nodeType, false );
+    }
+
+    @After
+    public void tearDown()
+        throws Exception
+    {
+        if (repository!=null)
+        {
+            repository.close( );
+        }
+
+    }
+
+    @Test
+    public void testJcrStatisticsQuery()
+        throws Exception
+    {
+        Calendar cal = Calendar.getInstance();
+        Date endTime = cal.getTime();
+        cal.add( Calendar.HOUR, -1 );
+        Date startTime = cal.getTime();
+
+        loadContentIntoRepo( TEST_REPO );
+        loadContentIntoRepo( "another-repo" );
+
+        DefaultRepositoryStatistics testedStatistics = new DefaultRepositoryStatistics();
+        testedStatistics.setNewFileCount( NEW_FILE_COUNT );
+        testedStatistics.setTotalFileCount( TOTAL_FILE_COUNT );
+        testedStatistics.setScanStartTime( startTime );
+        testedStatistics.setScanEndTime( endTime );
+
+        repository.populateStatistics( repository, TEST_REPO, testedStatistics );
+
+        DefaultRepositoryStatistics expectedStatistics = new DefaultRepositoryStatistics();
+        expectedStatistics.setNewFileCount( NEW_FILE_COUNT );
+        expectedStatistics.setTotalFileCount( TOTAL_FILE_COUNT );
+        expectedStatistics.setScanEndTime( endTime );
+        expectedStatistics.setScanStartTime( startTime );
+        expectedStatistics.setTotalArtifactFileSize( 95954585 );
+        expectedStatistics.setTotalArtifactCount( 269 );
+        expectedStatistics.setTotalGroupCount( 1 );
+        expectedStatistics.setTotalProjectCount( 43 );
+        expectedStatistics.setTotalCountForType( "zip", 1 );
+        expectedStatistics.setTotalCountForType( "gz", 1 ); // FIXME: should be tar.gz
+        expectedStatistics.setTotalCountForType( "java-source", 10 );
+        expectedStatistics.setTotalCountForType( "jar", 108 );
+        expectedStatistics.setTotalCountForType( "xml", 3 );
+        expectedStatistics.setTotalCountForType( "war", 2 );
+        expectedStatistics.setTotalCountForType( "pom", 144 );
+        expectedStatistics.setRepositoryId( TEST_REPO );
+
+        System.out.println(testedStatistics.getTotalCountForType());
+
+        assertEquals( NEW_FILE_COUNT, testedStatistics.getNewFileCount());
+        assertEquals( TOTAL_FILE_COUNT, testedStatistics.getTotalFileCount() );
+        assertEquals( endTime, testedStatistics.getScanEndTime() );
+        assertEquals( startTime, testedStatistics.getScanStartTime() );
+        assertEquals( 95954585, testedStatistics.getTotalArtifactFileSize() );
+        assertEquals( 269, testedStatistics.getTotalArtifactCount() );
+        assertEquals( 1, testedStatistics.getTotalGroupCount() );
+        assertEquals( 43, testedStatistics.getTotalProjectCount() );
+        assertEquals( 1, testedStatistics.getTotalCountForType( "zip" ) );
+        assertEquals( 1, testedStatistics.getTotalCountForType( "gz" ) );
+        assertEquals( 10, testedStatistics.getTotalCountForType( "java-source" ) );
+        assertEquals( 108, testedStatistics.getTotalCountForType( "jar" ) );
+        assertEquals( 3, testedStatistics.getTotalCountForType( "xml" ) );
+        assertEquals( 2, testedStatistics.getTotalCountForType( "war" ) );
+        assertEquals( 144, testedStatistics.getTotalCountForType( "pom" ) );
+        assertEquals( 10, testedStatistics.getTotalCountForType( "java-source" ) );
+
+
+    }
+
+    private void loadContentIntoRepo( String repoId )
+        throws RepositoryException, IOException
+    {
+        Node n = JcrUtils.getOrAddNode( session.getRootNode(), "repositories" );
+        n = JcrUtils.getOrAddNode( n, repoId );
+        n = JcrUtils.getOrAddNode( n, "content" );
+        n = JcrUtils.getOrAddNode( n, "org" );
+        n = JcrUtils.getOrAddNode( n, "apache" );
+
+        GZIPInputStream inputStream = new GZIPInputStream( getClass().getResourceAsStream( "/artifacts.xml.gz" ) );
+        session.importXML( n.getPath(), inputStream, ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW );
+        session.save();
+    }
+}
diff --git a/archiva-modules/plugins/metadata-store-jcr/src/test/resources/artifacts.xml.gz b/archiva-modules/plugins/metadata-store-jcr/src/test/resources/artifacts.xml.gz
new file mode 100644 (file)
index 0000000..0d8a41e
Binary files /dev/null and b/archiva-modules/plugins/metadata-store-jcr/src/test/resources/artifacts.xml.gz differ
index 2d20acacb249daeebfaec257872dadedf333af84..8265ed1eb5cff4c88925b1ebd755b2dd35091a34 100644 (file)
       <groupId>org.apache.archiva</groupId>
       <artifactId>metadata-repository-api</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.archiva</groupId>
+      <artifactId>metadata-statistics-api</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.apache.archiva</groupId>
       <artifactId>metadata-model-maven2</artifactId>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>
-    <dependency>
-      <groupId>javax.jcr</groupId>
-      <artifactId>jcr</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.jackrabbit</groupId>
-      <artifactId>jackrabbit-jcr-commons</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.apache.archiva</groupId>
       <artifactId>archiva-test-utils</artifactId>
       <artifactId>log4j-jcl</artifactId>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>org.apache.jackrabbit</groupId>
-      <artifactId>jackrabbit-core</artifactId>
-      <scope>test</scope>
-      <exclusions>
-        <exclusion>
-          <groupId>org.slf4j</groupId>
-          <artifactId>jcl-over-slf4j</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
     <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-all</artifactId>
index b05bea76712d7f6cd2ae6712f33420423a03080d..f7c4dcc847421593ecc45062ef292938932896ca 100644 (file)
@@ -19,13 +19,14 @@ package org.apache.archiva.metadata.repository.stats;
  * under the License.
  */
 
-import org.apache.archiva.metadata.model.ArtifactMetadata;
-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.stats.model.DefaultRepositoryStatistics;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsManager;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatisticsProvider;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryWalkingStatisticsProvider;
 import org.apache.commons.lang.time.StopWatch;
-import org.apache.jackrabbit.commons.JcrUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
@@ -33,20 +34,10 @@ import org.springframework.stereotype.Service;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.TimeZone;
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryManager;
-import javax.jcr.query.QueryResult;
-import javax.jcr.query.Row;
 
 /**
  *
@@ -59,11 +50,13 @@ public class DefaultRepositoryStatisticsManager
 
     private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone( "UTC" );
 
+    private RepositoryWalkingStatisticsProvider walkingProvider = new RepositoryWalkingStatisticsProvider();
+
     @Override
     public boolean hasStatistics( MetadataRepository metadataRepository, String repositoryId )
         throws MetadataRepositoryException
     {
-        return metadataRepository.hasMetadataFacet( repositoryId, RepositoryStatistics.FACET_ID );
+        return metadataRepository.hasMetadataFacet( repositoryId, DefaultRepositoryStatistics.FACET_ID );
     }
 
     @Override
@@ -73,7 +66,7 @@ public class DefaultRepositoryStatisticsManager
         StopWatch stopWatch = new StopWatch();
         stopWatch.start();
         // TODO: consider a more efficient implementation that directly gets the last one from the content repository
-        List<String> scans = metadataRepository.getMetadataFacets( repositoryId, RepositoryStatistics.FACET_ID );
+        List<String> scans = metadataRepository.getMetadataFacets( repositoryId, DefaultRepositoryStatistics.FACET_ID );
         if ( scans == null )
         {
             return null;
@@ -95,50 +88,12 @@ public class DefaultRepositoryStatisticsManager
         }
     }
 
-    private void walkRepository( MetadataRepository metadataRepository, RepositoryStatistics stats, String repositoryId,
-                                 String ns )
-        throws MetadataResolutionException
-    {
-        for ( String namespace : metadataRepository.getNamespaces( repositoryId, ns ) )
-        {
-            walkRepository( metadataRepository, stats, repositoryId, ns + "." + namespace );
-        }
-
-        Collection<String> projects = metadataRepository.getProjects( repositoryId, ns );
-        if ( !projects.isEmpty() )
-        {
-            stats.setTotalGroupCount( stats.getTotalGroupCount() + 1 );
-            stats.setTotalProjectCount( stats.getTotalProjectCount() + projects.size() );
-
-            for ( String project : projects )
-            {
-                for ( String version : metadataRepository.getProjectVersions( repositoryId, ns, project ) )
-                {
-                    for ( ArtifactMetadata artifact : metadataRepository.getArtifacts( repositoryId, ns, project,
-                                                                                       version ) )
-                    {
-                        stats.setTotalArtifactCount( stats.getTotalArtifactCount() + 1 );
-                        stats.setTotalArtifactFileSize( stats.getTotalArtifactFileSize() + artifact.getSize() );
-
-                        MavenArtifactFacet facet =
-                            (MavenArtifactFacet) artifact.getFacet( MavenArtifactFacet.FACET_ID );
-                        if ( facet != null )
-                        {
-                            String type = facet.getType();
-                            stats.setTotalCountForType( type, stats.getTotalCountForType( type ) + 1 );
-                        }
-                    }
-                }
-            }
-        }
-    }
-
     @Override
     public void addStatisticsAfterScan( MetadataRepository metadataRepository, String repositoryId, Date startTime,
                                         Date endTime, long totalFiles, long newFiles )
         throws MetadataRepositoryException
     {
-        RepositoryStatistics repositoryStatistics = new RepositoryStatistics();
+        DefaultRepositoryStatistics repositoryStatistics = new DefaultRepositoryStatistics();
         repositoryStatistics.setRepositoryId( repositoryId );
         repositoryStatistics.setScanStartTime( startTime );
         repositoryStatistics.setScanEndTime( endTime );
@@ -154,23 +109,14 @@ public class DefaultRepositoryStatisticsManager
 
         long startGather = System.currentTimeMillis();
 
-        // FIXME what about other implementations ?
-
-        if ( metadataRepository.canObtainAccess( Session.class ) )
+        if ( metadataRepository instanceof RepositoryStatisticsProvider)
         {
-            // TODO: this is currently very raw and susceptible to changes in content structure. Should we instead
-            //   depend directly on the plugin and interrogate the JCR repository's knowledge of the structure?
-            populateStatisticsFromJcr( (Session) metadataRepository.obtainAccess( Session.class ), repositoryId,
-                                       repositoryStatistics );
+            ((RepositoryStatisticsProvider)metadataRepository).populateStatistics( metadataRepository,
+                repositoryId, repositoryStatistics);
         }
         else
         {
-            // TODO:
-            //   if the file repository is used more permanently, we may seek a more efficient mechanism - e.g. we could
-            //   build an index, or store the aggregate information and update it on the fly. We can perhaps even walk
-            //   but retrieve less information to speed it up. In the mean time, we walk the repository using the
-            //   standard APIs
-            populateStatisticsFromRepositoryWalk( metadataRepository, repositoryId, repositoryStatistics );
+            walkingProvider.populateStatistics( metadataRepository, repositoryId, repositoryStatistics );
         }
 
         log.info( "Gathering statistics executed in {} ms",  ( System.currentTimeMillis() - startGather ) );
@@ -178,98 +124,11 @@ public class DefaultRepositoryStatisticsManager
         metadataRepository.addMetadataFacet( repositoryId, repositoryStatistics );
     }
 
-    private void populateStatisticsFromJcr( Session session, String repositoryId,
-                                            RepositoryStatistics repositoryStatistics )
-        throws MetadataRepositoryException
-    {
-        // TODO: these may be best as running totals, maintained by observations on the properties in JCR
-
-        try
-        {
-            QueryManager queryManager = session.getWorkspace().getQueryManager();
-
-            // TODO: JCR-SQL2 query will not complete on a large repo in Jackrabbit 2.2.0 - see JCR-2835
-            //    Using the JCR-SQL2 variants gives
-            //      "org.apache.lucene.search.BooleanQuery$TooManyClauses: maxClauseCount is set to 1024"
-//            String whereClause = "WHERE ISDESCENDANTNODE([/repositories/" + repositoryId + "/content])";
-//            Query query = queryManager.createQuery( "SELECT size FROM [archiva:artifact] " + whereClause,
-//                                                    Query.JCR_SQL2 );
-            String whereClause = "WHERE jcr:path LIKE '/repositories/" + repositoryId + "/content/%'";
-            Query query = queryManager.createQuery( "SELECT size FROM archiva:artifact " + whereClause, Query.SQL );
-
-            QueryResult queryResult = query.execute();
-
-            Map<String, Integer> totalByType = new HashMap<>();
-            long totalSize = 0, totalArtifacts = 0;
-            for ( Row row : JcrUtils.getRows( queryResult ) )
-            {
-                Node n = row.getNode();
-                totalSize += row.getValue( "size" ).getLong();
-
-                String type;
-                if ( n.hasNode( MavenArtifactFacet.FACET_ID ) )
-                {
-                    Node facetNode = n.getNode( MavenArtifactFacet.FACET_ID );
-                    type = facetNode.getProperty( "type" ).getString();
-                }
-                else
-                {
-                    type = "Other";
-                }
-                Integer prev = totalByType.get( type );
-                totalByType.put( type, prev != null ? prev + 1 : 1 );
-
-                totalArtifacts++;
-            }
-
-            repositoryStatistics.setTotalArtifactCount( totalArtifacts );
-            repositoryStatistics.setTotalArtifactFileSize( totalSize );
-            for ( Map.Entry<String, Integer> entry : totalByType.entrySet() )
-            {
-                repositoryStatistics.setTotalCountForType( entry.getKey(), entry.getValue() );
-            }
-
-            // The query ordering is a trick to ensure that the size is correct, otherwise due to lazy init it will be -1
-//            query = queryManager.createQuery( "SELECT * FROM [archiva:project] " + whereClause, Query.JCR_SQL2 );
-            query = queryManager.createQuery( "SELECT * FROM archiva:project " + whereClause + " ORDER BY jcr:score",
-                                              Query.SQL );
-            repositoryStatistics.setTotalProjectCount( query.execute().getRows().getSize() );
-
-//            query = queryManager.createQuery(
-//                "SELECT * FROM [archiva:namespace] " + whereClause + " AND namespace IS NOT NULL", Query.JCR_SQL2 );
-            query = queryManager.createQuery(
-                "SELECT * FROM archiva:namespace " + whereClause + " AND namespace IS NOT NULL ORDER BY jcr:score",
-                Query.SQL );
-            repositoryStatistics.setTotalGroupCount( query.execute().getRows().getSize() );
-        }
-        catch ( RepositoryException e )
-        {
-            throw new MetadataRepositoryException( e.getMessage(), e );
-        }
-    }
-
-    private void populateStatisticsFromRepositoryWalk( MetadataRepository metadataRepository, String repositoryId,
-                                                       RepositoryStatistics repositoryStatistics )
-        throws MetadataRepositoryException
-    {
-        try
-        {
-            for ( String ns : metadataRepository.getRootNamespaces( repositoryId ) )
-            {
-                walkRepository( metadataRepository, repositoryStatistics, repositoryId, ns );
-            }
-        }
-        catch ( MetadataResolutionException e )
-        {
-            throw new MetadataRepositoryException( e.getMessage(), e );
-        }
-    }
-
     @Override
     public void deleteStatistics( MetadataRepository metadataRepository, String repositoryId )
         throws MetadataRepositoryException
     {
-        metadataRepository.removeMetadataFacets( repositoryId, RepositoryStatistics.FACET_ID );
+        metadataRepository.removeMetadataFacets( repositoryId, DefaultRepositoryStatistics.FACET_ID );
     }
 
     @Override
@@ -278,7 +137,7 @@ public class DefaultRepositoryStatisticsManager
         throws MetadataRepositoryException
     {
         List<RepositoryStatistics> results = new ArrayList<>();
-        List<String> list = metadataRepository.getMetadataFacets( repositoryId, RepositoryStatistics.FACET_ID );
+        List<String> list = metadataRepository.getMetadataFacets( repositoryId, DefaultRepositoryStatistics.FACET_ID );
         Collections.sort( list, Collections.reverseOrder() );
         for ( String name : list )
         {
@@ -290,7 +149,7 @@ public class DefaultRepositoryStatisticsManager
                 {
                     RepositoryStatistics stats =
                         (RepositoryStatistics) metadataRepository.getMetadataFacet( repositoryId,
-                                                                                    RepositoryStatistics.FACET_ID,
+                                                                                    DefaultRepositoryStatistics.FACET_ID,
                                                                                     name );
                     results.add( stats );
                 }
@@ -306,7 +165,7 @@ public class DefaultRepositoryStatisticsManager
 
     private static SimpleDateFormat createNameFormat()
     {
-        SimpleDateFormat fmt = new SimpleDateFormat( RepositoryStatistics.SCAN_TIMESTAMP_FORMAT );
+        SimpleDateFormat fmt = new SimpleDateFormat( DefaultRepositoryStatistics.SCAN_TIMESTAMP_FORMAT );
         fmt.setTimeZone( UTC_TIME_ZONE );
         return fmt;
     }
diff --git a/archiva-modules/plugins/repository-statistics/src/main/java/org/apache/archiva/metadata/repository/stats/RepositoryStatistics.java b/archiva-modules/plugins/repository-statistics/src/main/java/org/apache/archiva/metadata/repository/stats/RepositoryStatistics.java
deleted file mode 100644 (file)
index 71cee37..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-package org.apache.archiva.metadata.repository.stats;
-
-/*
- * 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 java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.TimeZone;
-
-public class RepositoryStatistics
-    implements MetadataFacet
-{
-    private Date scanEndTime;
-
-    private Date scanStartTime;
-
-    private long totalArtifactCount;
-
-    private long totalArtifactFileSize;
-
-    private long totalFileCount;
-
-    private long totalGroupCount;
-
-    private long totalProjectCount;
-
-    private long newFileCount;
-
-    public static String FACET_ID = "org.apache.archiva.metadata.repository.stats";
-
-    static final String SCAN_TIMESTAMP_FORMAT = "yyyy/MM/dd/HHmmss.SSS";
-
-    private Map<String, Long> totalCountForType = new ZeroForNullHashMap<String, Long>();
-
-    private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone( "UTC" );
-
-    private String repositoryId;
-
-    public Date getScanEndTime()
-    {
-        return scanEndTime;
-    }
-
-    public void setScanEndTime( Date scanEndTime )
-    {
-        this.scanEndTime = scanEndTime;
-    }
-
-    public Date getScanStartTime()
-    {
-        return scanStartTime;
-    }
-
-    public void setScanStartTime( Date scanStartTime )
-    {
-        this.scanStartTime = scanStartTime;
-    }
-
-    public long getTotalArtifactCount()
-    {
-        return totalArtifactCount;
-    }
-
-    public void setTotalArtifactCount( long totalArtifactCount )
-    {
-        this.totalArtifactCount = totalArtifactCount;
-    }
-
-    public long getTotalArtifactFileSize()
-    {
-        return totalArtifactFileSize;
-    }
-
-    public void setTotalArtifactFileSize( long totalArtifactFileSize )
-    {
-        this.totalArtifactFileSize = totalArtifactFileSize;
-    }
-
-    public long getTotalFileCount()
-    {
-        return totalFileCount;
-    }
-
-    public void setTotalFileCount( long totalFileCount )
-    {
-        this.totalFileCount = totalFileCount;
-    }
-
-    public long getTotalGroupCount()
-    {
-        return totalGroupCount;
-    }
-
-    public void setTotalGroupCount( long totalGroupCount )
-    {
-        this.totalGroupCount = totalGroupCount;
-    }
-
-    public long getTotalProjectCount()
-    {
-        return totalProjectCount;
-    }
-
-    public void setTotalProjectCount( long totalProjectCount )
-    {
-        this.totalProjectCount = totalProjectCount;
-    }
-
-    public void setNewFileCount( long newFileCount )
-    {
-        this.newFileCount = newFileCount;
-    }
-
-    public long getNewFileCount()
-    {
-        return newFileCount;
-    }
-
-    public long getDuration()
-    {
-        return scanEndTime.getTime() - scanStartTime.getTime();
-    }
-
-    public String getRepositoryId()
-    {
-        return repositoryId;
-    }
-
-    public void setRepositoryId( String repositoryId )
-    {
-        this.repositoryId = repositoryId;
-    }
-
-    @Override
-    public String getFacetId()
-    {
-        return FACET_ID;
-    }
-
-    @Override
-    public String getName()
-    {
-        return createNameFormat().format( scanStartTime );
-    }
-
-    private static SimpleDateFormat createNameFormat()
-    {
-        SimpleDateFormat fmt = new SimpleDateFormat( SCAN_TIMESTAMP_FORMAT );
-        fmt.setTimeZone( UTC_TIME_ZONE );
-        return fmt;
-    }
-
-    @Override
-    public Map<String, String> toProperties()
-    {
-        Map<String, String> properties = new HashMap<>();
-        properties.put( "scanEndTime", String.valueOf( scanEndTime.getTime() ) );
-        properties.put( "scanStartTime", String.valueOf( scanStartTime.getTime() ) );
-        properties.put( "totalArtifactCount", String.valueOf( totalArtifactCount ) );
-        properties.put( "totalArtifactFileSize", String.valueOf( totalArtifactFileSize ) );
-        properties.put( "totalFileCount", String.valueOf( totalFileCount ) );
-        properties.put( "totalGroupCount", String.valueOf( totalGroupCount ) );
-        properties.put( "totalProjectCount", String.valueOf( totalProjectCount ) );
-        properties.put( "newFileCount", String.valueOf( newFileCount ) );
-        properties.put( "repositoryId", repositoryId );
-        for ( Map.Entry<String, Long> entry : totalCountForType.entrySet() )
-        {
-            properties.put( "count-" + entry.getKey(), String.valueOf( entry.getValue() ) );
-        }
-        return properties;
-    }
-
-    @Override
-    public void fromProperties( Map<String, String> properties )
-    {
-        scanEndTime = new Date( Long.parseLong( properties.get( "scanEndTime" ) ) );
-        scanStartTime = new Date( Long.parseLong( properties.get( "scanStartTime" ) ) );
-        totalArtifactCount = Long.parseLong( properties.get( "totalArtifactCount" ) );
-        totalArtifactFileSize = Long.parseLong( properties.get( "totalArtifactFileSize" ) );
-        totalFileCount = Long.parseLong( properties.get( "totalFileCount" ) );
-        totalGroupCount = Long.parseLong( properties.get( "totalGroupCount" ) );
-        totalProjectCount = Long.parseLong( properties.get( "totalProjectCount" ) );
-        newFileCount = Long.parseLong( properties.get( "newFileCount" ) );
-        repositoryId = properties.get( "repositoryId" );
-        totalCountForType.clear();
-        for ( Map.Entry<String, String> entry : properties.entrySet() )
-        {
-            if ( entry.getKey().startsWith( "count-" ) )
-            {
-                totalCountForType.put( entry.getKey().substring( 6 ), Long.valueOf( entry.getValue() ) );
-            }
-        }
-    }
-
-    @Override
-    public boolean equals( Object o )
-    {
-        if ( this == o )
-        {
-            return true;
-        }
-        if ( o == null || getClass() != o.getClass() )
-        {
-            return false;
-        }
-
-        RepositoryStatistics that = (RepositoryStatistics) o;
-
-        if ( newFileCount != that.newFileCount )
-        {
-            return false;
-        }
-        if ( totalArtifactCount != that.totalArtifactCount )
-        {
-            return false;
-        }
-        if ( totalArtifactFileSize != that.totalArtifactFileSize )
-        {
-            return false;
-        }
-        if ( totalFileCount != that.totalFileCount )
-        {
-            return false;
-        }
-        if ( totalGroupCount != that.totalGroupCount )
-        {
-            return false;
-        }
-        if ( totalProjectCount != that.totalProjectCount )
-        {
-            return false;
-        }
-        if ( !scanEndTime.equals( that.scanEndTime ) )
-        {
-            return false;
-        }
-        if ( !scanStartTime.equals( that.scanStartTime ) )
-        {
-            return false;
-        }
-        if ( !totalCountForType.equals( that.totalCountForType ) )
-        {
-            return false;
-        }
-        if ( !repositoryId.equals( that.repositoryId ) )
-        {
-            return false;
-        }
-
-        return true;
-    }
-
-    @Override
-    public int hashCode()
-    {
-        int result = scanEndTime.hashCode();
-        result = 31 * result + scanStartTime.hashCode();
-        result = 31 * result + (int) ( totalArtifactCount ^ ( totalArtifactCount >>> 32 ) );
-        result = 31 * result + (int) ( totalArtifactFileSize ^ ( totalArtifactFileSize >>> 32 ) );
-        result = 31 * result + (int) ( totalFileCount ^ ( totalFileCount >>> 32 ) );
-        result = 31 * result + (int) ( totalGroupCount ^ ( totalGroupCount >>> 32 ) );
-        result = 31 * result + (int) ( totalProjectCount ^ ( totalProjectCount >>> 32 ) );
-        result = 31 * result + (int) ( newFileCount ^ ( newFileCount >>> 32 ) );
-        result = 31 * result + totalCountForType.hashCode();
-        result = 31 * result + repositoryId.hashCode();
-        return result;
-    }
-
-    @Override
-    public String toString()
-    {
-        return "RepositoryStatistics{" + "scanEndTime=" + scanEndTime + ", scanStartTime=" + scanStartTime +
-            ", totalArtifactCount=" + totalArtifactCount + ", totalArtifactFileSize=" + totalArtifactFileSize +
-            ", totalFileCount=" + totalFileCount + ", totalGroupCount=" + totalGroupCount + ", totalProjectCount=" +
-            totalProjectCount + ", newFileCount=" + newFileCount + ", totalCountForType=" + totalCountForType + ", " +
-            "repositoryId=" + repositoryId + '}';
-    }
-
-    public Map<String, Long> getTotalCountForType()
-    {
-        return totalCountForType;
-    }
-
-    public long getTotalCountForType( String type )
-    {
-        return totalCountForType.get( type );
-    }
-
-    public void setTotalCountForType( String type, long count )
-    {
-        totalCountForType.put( type.replaceAll( "-", "_" ).replaceAll( "\\.", "_" ), count );
-    }
-    
-    private static final class ZeroForNullHashMap<K, V extends Long> extends HashMap<K, V>
-    {   
-        @Override
-        public V get(Object key) {
-            V value = super.get( key );
-            
-            return value != null ? value : ( V ) Long.valueOf( 0L );
-        }
-    }
-}
index 1984646880f7ba488bdf4c40dd05559094630d0d..ceb9118035a7c9df2c2df879c9f9f27c3bb08485 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.archiva.metadata.repository.stats;
 
 import org.apache.archiva.metadata.model.MetadataFacet;
 import org.apache.archiva.metadata.model.MetadataFacetFactory;
+import org.apache.archiva.metadata.repository.stats.model.DefaultRepositoryStatistics;
 import org.springframework.stereotype.Service;
 
 /**
@@ -33,12 +34,12 @@ public class RepositoryStatisticsFactory
     @Override
     public MetadataFacet createMetadataFacet()
     {
-        return new RepositoryStatistics();
+        return new DefaultRepositoryStatistics();
     }
 
     @Override
     public MetadataFacet createMetadataFacet( String repositoryId, String name )
     {
-        return new RepositoryStatistics();
+        return new DefaultRepositoryStatistics();
     }
 }
\ No newline at end of file
diff --git a/archiva-modules/plugins/repository-statistics/src/main/java/org/apache/archiva/metadata/repository/stats/RepositoryStatisticsManager.java b/archiva-modules/plugins/repository-statistics/src/main/java/org/apache/archiva/metadata/repository/stats/RepositoryStatisticsManager.java
deleted file mode 100644 (file)
index 1833264..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.apache.archiva.metadata.repository.stats;
-
-/*
- * 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.repository.MetadataRepository;
-import org.apache.archiva.metadata.repository.MetadataRepositoryException;
-
-import java.util.Date;
-import java.util.List;
-
-public interface RepositoryStatisticsManager
-{
-    RepositoryStatistics getLastStatistics( MetadataRepository metadataRepository, String repositoryId )
-        throws MetadataRepositoryException;
-
-    boolean hasStatistics( MetadataRepository metadataRepository, String repositoryId )
-        throws MetadataRepositoryException;
-
-    void addStatisticsAfterScan( MetadataRepository metadataRepository, String repositoryId, Date startTime,
-                                 Date endTime, long totalFiles, long newFiles )
-        throws MetadataRepositoryException;
-
-    void deleteStatistics( MetadataRepository metadataRepository, String repositoryId )
-        throws MetadataRepositoryException;
-
-    List<RepositoryStatistics> getStatisticsInRange( MetadataRepository metadataRepository, String repositoryId,
-                                                     Date startTime, Date endTime )
-        throws MetadataRepositoryException;
-}
diff --git a/archiva-modules/plugins/repository-statistics/src/test/java/org/apache/archiva/metadata/repository/stats/JcrRepositoryStatisticsGatheringTest.java b/archiva-modules/plugins/repository-statistics/src/test/java/org/apache/archiva/metadata/repository/stats/JcrRepositoryStatisticsGatheringTest.java
deleted file mode 100644 (file)
index 1a46b87..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-package org.apache.archiva.metadata.repository.stats;
-
-/*
- * 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 junit.framework.TestCase;
-import org.apache.archiva.metadata.repository.MetadataRepository;
-import org.apache.archiva.metadata.repository.RepositorySessionFactory;
-import org.apache.commons.io.FileUtils;
-import org.apache.jackrabbit.commons.JcrUtils;
-import org.apache.jackrabbit.core.TransientRepository;
-
-import javax.inject.Inject;
-import javax.jcr.ImportUUIDBehavior;
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.SimpleCredentials;
-import javax.jcr.Workspace;
-import javax.jcr.nodetype.NodeTypeManager;
-import javax.jcr.nodetype.NodeTypeTemplate;
-import java.io.File;
-import java.io.IOException;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.zip.GZIPInputStream;
-
-import org.apache.archiva.test.utils.ArchivaBlockJUnit4ClassRunner;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.mockito.Mockito.*;
-
-@RunWith( ArchivaBlockJUnit4ClassRunner.class )
-public class JcrRepositoryStatisticsGatheringTest
-    extends TestCase
-{
-    private static final int TOTAL_FILE_COUNT = 1000;
-
-    private static final int NEW_FILE_COUNT = 500;
-
-    private static final String TEST_REPO = "test-repo";
-
-    private RepositoryStatisticsManager repositoryStatisticsManager;
-
-    private MetadataRepository metadataRepository;
-
-    @Inject
-    private RepositorySessionFactory repositorySessionFactory;
-
-    private Session session;
-
-    @Override
-    @Before
-    public void setUp()
-        throws Exception
-    {
-        super.setUp();
-
-        File confFile = new File( "src/test/repository.xml" );
-        File dir = new File( "target/jcr" );
-        FileUtils.deleteDirectory( dir );
-
-        assertTrue( confFile.exists() );
-        assertFalse( dir.exists() );
-
-        TransientRepository repository = new TransientRepository( confFile, dir );
-        session = repository.login( new SimpleCredentials( "username", "password".toCharArray() ) );
-
-        // TODO: perhaps have an archiva-jcr-utils module shared by these plugins that does this and can contain
-        //      structure information
-        Workspace workspace = session.getWorkspace();
-        NamespaceRegistry registry = workspace.getNamespaceRegistry();
-        registry.registerNamespace( "archiva", "http://archiva.apache.org/jcr/" );
-
-        NodeTypeManager nodeTypeManager = workspace.getNodeTypeManager();
-        registerMixinNodeType( nodeTypeManager, "archiva:namespace" );
-        registerMixinNodeType( nodeTypeManager, "archiva:project" );
-        registerMixinNodeType( nodeTypeManager, "archiva:projectVersion" );
-        registerMixinNodeType( nodeTypeManager, "archiva:artifact" );
-        registerMixinNodeType( nodeTypeManager, "archiva:facet" );
-
-        metadataRepository = mock( MetadataRepository.class );
-        when( metadataRepository.canObtainAccess( Session.class ) ).thenReturn( true );
-        when( metadataRepository.obtainAccess( Session.class ) ).thenReturn( session );
-
-        repositoryStatisticsManager = new DefaultRepositoryStatisticsManager();
-    }
-
-    private static void registerMixinNodeType( NodeTypeManager nodeTypeManager, String type )
-        throws RepositoryException
-    {
-        NodeTypeTemplate nodeType = nodeTypeManager.createNodeTypeTemplate();
-        nodeType.setMixin( true );
-        nodeType.setName( type );
-        nodeTypeManager.registerNodeType( nodeType, false );
-    }
-
-    @Override
-    @After
-    public void tearDown()
-        throws Exception
-    {
-        if ( session != null )
-        {
-            session.logout();
-        }
-
-        super.tearDown();
-    }
-
-    @Test
-    public void testJcrStatisticsQuery()
-        throws Exception
-    {
-        Calendar cal = Calendar.getInstance();
-        Date endTime = cal.getTime();
-        cal.add( Calendar.HOUR, -1 );
-        Date startTime = cal.getTime();
-
-        loadContentIntoRepo( TEST_REPO );
-        loadContentIntoRepo( "another-repo" );
-
-        repositoryStatisticsManager.addStatisticsAfterScan( metadataRepository, TEST_REPO, startTime, endTime,
-                                                            TOTAL_FILE_COUNT, NEW_FILE_COUNT );
-
-        RepositoryStatistics expectedStatistics = new RepositoryStatistics();
-        expectedStatistics.setNewFileCount( NEW_FILE_COUNT );
-        expectedStatistics.setTotalFileCount( TOTAL_FILE_COUNT );
-        expectedStatistics.setScanEndTime( endTime );
-        expectedStatistics.setScanStartTime( startTime );
-        expectedStatistics.setTotalArtifactFileSize( 95954585 );
-        expectedStatistics.setTotalArtifactCount( 269 );
-        expectedStatistics.setTotalGroupCount( 1 );
-        expectedStatistics.setTotalProjectCount( 43 );
-        expectedStatistics.setTotalCountForType( "zip", 1 );
-        expectedStatistics.setTotalCountForType( "gz", 1 ); // FIXME: should be tar.gz
-        expectedStatistics.setTotalCountForType( "java-source", 10 );
-        expectedStatistics.setTotalCountForType( "jar", 108 );
-        expectedStatistics.setTotalCountForType( "xml", 3 );
-        expectedStatistics.setTotalCountForType( "war", 2 );
-        expectedStatistics.setTotalCountForType( "pom", 144 );
-        expectedStatistics.setRepositoryId( TEST_REPO );
-
-        verify( metadataRepository ).addMetadataFacet( TEST_REPO, expectedStatistics );
-    }
-
-    private void loadContentIntoRepo( String repoId )
-        throws RepositoryException, IOException
-    {
-        Node n = JcrUtils.getOrAddNode( session.getRootNode(), "repositories" );
-        n = JcrUtils.getOrAddNode( n, repoId );
-        n = JcrUtils.getOrAddNode( n, "content" );
-        n = JcrUtils.getOrAddNode( n, "org" );
-        n = JcrUtils.getOrAddNode( n, "apache" );
-
-        GZIPInputStream inputStream = new GZIPInputStream( getClass().getResourceAsStream( "/artifacts.xml.gz" ) );
-        session.importXML( n.getPath(), inputStream, ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW );
-        session.save();
-    }
-}
index 2ec08e6b5a51c9a45a7695bdfb8f5ebfd51e5f27..b0a1742e9f13cdb5a2e105626651dac42c31d903 100644 (file)
@@ -23,16 +23,14 @@ import junit.framework.TestCase;
 import org.apache.archiva.metadata.model.ArtifactMetadata;
 import org.apache.archiva.metadata.model.maven2.MavenArtifactFacet;
 import org.apache.archiva.metadata.repository.MetadataRepository;
+import org.apache.archiva.metadata.repository.stats.model.DefaultRepositoryStatistics;
+import org.apache.archiva.metadata.repository.stats.model.RepositoryStatistics;
 import org.apache.archiva.test.utils.ArchivaBlockJUnit4ClassRunner;
 import org.easymock.IMocksControl;
-
-import static org.easymock.EasyMock.*;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import javax.jcr.Session;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -43,6 +41,9 @@ import java.util.List;
 import java.util.Map;
 import java.util.TimeZone;
 
+import static org.easymock.EasyMock.createControl;
+import static org.easymock.EasyMock.expect;
+
 @RunWith( ArchivaBlockJUnit4ClassRunner.class )
 public class RepositoryStatisticsManagerTest
     extends TestCase
@@ -65,7 +66,7 @@ public class RepositoryStatisticsManagerTest
 
     private static SimpleDateFormat createTimestampFormat()
     {
-        SimpleDateFormat fmt = new SimpleDateFormat( RepositoryStatistics.SCAN_TIMESTAMP_FORMAT );
+        SimpleDateFormat fmt = new SimpleDateFormat( DefaultRepositoryStatistics.SCAN_TIMESTAMP_FORMAT );
         fmt.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
         return fmt;
     }
@@ -90,9 +91,10 @@ public class RepositoryStatisticsManagerTest
         Date startTime = TIMESTAMP_FORMAT.parse( SECOND_TEST_SCAN );
         Date endTime = new Date( startTime.getTime() + 60000 );
 
-        RepositoryStatistics stats = new RepositoryStatistics();
-        stats.setScanStartTime( startTime );
-        stats.setScanEndTime( endTime );
+        DefaultRepositoryStatistics defStats = new DefaultRepositoryStatistics();
+        defStats.setScanStartTime( startTime );
+        defStats.setScanEndTime( endTime );
+        RepositoryStatistics stats = defStats;
         stats.setTotalArtifactFileSize( 1314527915L );
         stats.setNewFileCount( 123 );
         stats.setTotalArtifactCount( 10386 );
@@ -101,10 +103,10 @@ public class RepositoryStatisticsManagerTest
         stats.setTotalFileCount( 56229 );
 
 
-        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, RepositoryStatistics.FACET_ID ) ).andReturn(
+        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID ) ).andReturn(
             Arrays.asList( FIRST_TEST_SCAN, SECOND_TEST_SCAN ) );
 
-        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, RepositoryStatistics.FACET_ID,
+        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID,
                                                      SECOND_TEST_SCAN ) ).andReturn( stats );
 
         metadataRepositoryControl.replay();
@@ -129,7 +131,7 @@ public class RepositoryStatisticsManagerTest
         throws Exception
     {
 
-        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, RepositoryStatistics.FACET_ID ) ).andReturn(
+        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID ) ).andReturn(
             Collections.<String>emptyList() );
         metadataRepositoryControl.replay();
 
@@ -152,14 +154,12 @@ public class RepositoryStatisticsManagerTest
 
         metadataRepository.addMetadataFacet( TEST_REPO_ID, stats );
 
-        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, RepositoryStatistics.FACET_ID ) ).andReturn(
+        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID ) ).andReturn(
             Arrays.asList( stats.getName() ) );
 
-        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, RepositoryStatistics.FACET_ID,
+        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID,
                                                      stats.getName() ) ).andReturn( stats );
 
-        expect( metadataRepository.canObtainAccess( Session.class ) ).andReturn( false );
-
         metadataRepositoryControl.replay();
 
         repositoryStatisticsManager.addStatisticsAfterScan( metadataRepository, TEST_REPO_ID, startTime, current, 56345,
@@ -188,25 +188,24 @@ public class RepositoryStatisticsManagerTest
         Date current = new Date();
 
         Date startTime1 = new Date( current.getTime() - 12345 );
-        RepositoryStatistics stats1 = createTestStats( startTime1, new Date( current.getTime() - 6000 ) );
+        DefaultRepositoryStatistics stats1 = createTestStats( startTime1, new Date( current.getTime() - 6000 ) );
         metadataRepository.addMetadataFacet( TEST_REPO_ID, stats1 );
 
         Date startTime2 = new Date( current.getTime() - 3000 );
-        RepositoryStatistics stats2 = createTestStats( startTime2, current );
+        DefaultRepositoryStatistics stats2 = createTestStats( startTime2, current );
         metadataRepository.addMetadataFacet( TEST_REPO_ID, stats2 );
 
 
-        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, RepositoryStatistics.FACET_ID ) ).andReturn(
+        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID ) ).andReturn(
             Arrays.asList( stats1.getName(), stats2.getName() ) );
 
-        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, RepositoryStatistics.FACET_ID,
+        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID,
                                                      stats2.getName() ) ).andReturn( stats2 );
-        metadataRepository.removeMetadataFacets( TEST_REPO_ID, RepositoryStatistics.FACET_ID );
+        metadataRepository.removeMetadataFacets( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID );
 
-        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, RepositoryStatistics.FACET_ID ) ).andReturn(
+        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID ) ).andReturn(
             Collections.<String>emptyList() );
 
-        expect( metadataRepository.canObtainAccess( Session.class ) ).andReturn( false ).times( 2 );
         metadataRepositoryControl.replay();
 
         repositoryStatisticsManager.addStatisticsAfterScan( metadataRepository, TEST_REPO_ID, startTime1,
@@ -228,9 +227,9 @@ public class RepositoryStatisticsManagerTest
         throws Exception
     {
 
-        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, RepositoryStatistics.FACET_ID ) ).andReturn(
+        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID ) ).andReturn(
             Collections.<String>emptyList() ).times( 2 );
-        metadataRepository.removeMetadataFacets( TEST_REPO_ID, RepositoryStatistics.FACET_ID );
+        metadataRepository.removeMetadataFacets( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID );
 
         metadataRepositoryControl.replay();
 
@@ -257,15 +256,14 @@ public class RepositoryStatisticsManagerTest
 
         ArrayList<String> keys = new ArrayList<>( statsCreated.keySet() );
 
-        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, RepositoryStatistics.FACET_ID ) ).andReturn( keys );
+        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID ) ).andReturn( keys );
 
         // only match the middle one
         String key = keys.get( 1 );
 
-        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, RepositoryStatistics.FACET_ID, key ) ).andReturn(
+        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID, key ) ).andReturn(
             statsCreated.get( key ) );
 
-        expect( metadataRepository.canObtainAccess( Session.class ) ).andReturn( false ).times( 3 );
 
         metadataRepositoryControl.replay();
 
@@ -301,19 +299,18 @@ public class RepositoryStatisticsManagerTest
 
         List<String> keys = new ArrayList<>( statsCreated.keySet() );
 
-        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, RepositoryStatistics.FACET_ID ) ).andReturn( keys );
+        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID ) ).andReturn( keys );
 
         String key = keys.get( 1 );
 
-        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, RepositoryStatistics.FACET_ID, key ) ).andReturn(
+        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID, key ) ).andReturn(
             statsCreated.get( key ) );
 
         key = keys.get( 2 );
 
-        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, RepositoryStatistics.FACET_ID, key ) ).andReturn(
+        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID, key ) ).andReturn(
             statsCreated.get( key ) );
 
-        expect( metadataRepository.canObtainAccess( Session.class ) ).andReturn( false ).times( 3 );
 
         metadataRepositoryControl.replay();
 
@@ -349,19 +346,17 @@ public class RepositoryStatisticsManagerTest
 
         List<String> keys = new ArrayList<>( statsCreated.keySet() );
 
-        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, RepositoryStatistics.FACET_ID ) ).andReturn( keys );
+        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID ) ).andReturn( keys );
 
         String key = keys.get( 0 );
 
-        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, RepositoryStatistics.FACET_ID, key ) ).andReturn(
+        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID, key ) ).andReturn(
             statsCreated.get( key ) );
         key = keys.get( 1 );
 
-        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, RepositoryStatistics.FACET_ID, key ) ).andReturn(
+        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID, key ) ).andReturn(
             statsCreated.get( key ) );
 
-        expect( metadataRepository.canObtainAccess( Session.class ) ).andReturn( false ).times( 3 );
-
         metadataRepositoryControl.replay();
 
         for ( RepositoryStatistics stats : statsCreated.values() )
@@ -397,23 +392,21 @@ public class RepositoryStatisticsManagerTest
 
         ArrayList<String> keys = new ArrayList<>( statsCreated.keySet() );
 
-        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, RepositoryStatistics.FACET_ID ) ).andReturn( keys );
+        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID ) ).andReturn( keys );
 
         String key = keys.get( 0 );
 
-        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, RepositoryStatistics.FACET_ID, key ) ).andReturn(
+        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID, key ) ).andReturn(
             statsCreated.get( key ) );
         key = keys.get( 1 );
 
-        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, RepositoryStatistics.FACET_ID, key ) ).andReturn(
+        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID, key ) ).andReturn(
             statsCreated.get( key ) );
         key = keys.get( 2 );
 
-        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, RepositoryStatistics.FACET_ID, key ) ).andReturn(
+        expect( metadataRepository.getMetadataFacet( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID, key ) ).andReturn(
             statsCreated.get( key ) );
 
-        expect( metadataRepository.canObtainAccess( Session.class ) ).andReturn( false ).times( 3 );
-
         metadataRepositoryControl.replay();
 
         for ( RepositoryStatistics stats : statsCreated.values() )
@@ -449,9 +442,7 @@ public class RepositoryStatisticsManagerTest
 
         ArrayList<String> keys = new ArrayList<>( statsCreated.keySet() );
 
-        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, RepositoryStatistics.FACET_ID ) ).andReturn( keys );
-
-        expect( metadataRepository.canObtainAccess( Session.class ) ).andReturn( false ).times( 3 );
+        expect( metadataRepository.getMetadataFacets( TEST_REPO_ID, DefaultRepositoryStatistics.FACET_ID ) ).andReturn( keys );
 
         metadataRepositoryControl.replay();
 
@@ -475,7 +466,7 @@ public class RepositoryStatisticsManagerTest
     private void addStats( Date startTime, Date endTime )
         throws Exception
     {
-        RepositoryStatistics stats = createTestStats( startTime, endTime );
+        DefaultRepositoryStatistics stats = createTestStats( startTime, endTime );
         metadataRepository.addMetadataFacet( TEST_REPO_ID, stats );
         statsCreated.put( stats.getName(), stats );
     }
@@ -498,9 +489,9 @@ public class RepositoryStatisticsManagerTest
         return metadata;
     }
 
-    private RepositoryStatistics createTestStats( Date startTime, Date endTime )
+    private DefaultRepositoryStatistics createTestStats( Date startTime, Date endTime )
     {
-        RepositoryStatistics stats = new RepositoryStatistics();
+        DefaultRepositoryStatistics stats = new DefaultRepositoryStatistics();
         stats.setRepositoryId( TEST_REPO_ID );
         stats.setScanStartTime( startTime );
         stats.setScanEndTime( endTime );
diff --git a/pom.xml b/pom.xml
index 8e12a4c54a39cb756fa896fdb868d9155f181528..b7d572313dc82bceac20cc236a2900ce5072de89 100644 (file)
--- a/pom.xml
+++ b/pom.xml
         <artifactId>metadata-repository-api</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.archiva</groupId>
+        <artifactId>metadata-statistics-api</artifactId>
+        <version>${project.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.archiva</groupId>
         <artifactId>metadata-repository-api</artifactId>