]> source.dussan.org Git - archiva.git/blob
9233b07b514939c22e55a45fb84502cd85e5a73e
[archiva.git] /
1 package org.apache.archiva.metadata.repository.stats;
2
3 /*
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements.  See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership.  The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License"); you may not use this file except in compliance
10  * with the License.  You may obtain a copy of the License at
11  *
12  *   http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  * KIND, either express or implied.  See the License for the
18  * specific language governing permissions and limitations
19  * under the License.
20  */
21
22 import java.text.ParseException;
23 import java.text.SimpleDateFormat;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.Date;
28 import java.util.List;
29 import java.util.TimeZone;
30
31 import org.apache.archiva.metadata.model.ArtifactMetadata;
32 import org.apache.archiva.metadata.repository.MetadataRepository;
33 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
34 import org.apache.maven.archiva.repository.RepositoryContentFactory;
35 import org.apache.maven.archiva.repository.RepositoryException;
36 import org.apache.maven.archiva.repository.layout.LayoutException;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * @plexus.component role="org.apache.archiva.metadata.repository.stats.RepositoryStatisticsManager" role-hint="default"
42  */
43 public class DefaultRepositoryStatisticsManager
44     implements RepositoryStatisticsManager
45 {
46     private static final Logger log = LoggerFactory.getLogger( DefaultRepositoryStatisticsManager.class );
47
48     /**
49      * @plexus.requirement
50      */
51     private MetadataRepository metadataRepository;
52
53     /**
54      * @plexus.requirement
55      */
56     private RepositoryContentFactory repositoryContentFactory;
57
58     private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone( "UTC" );
59
60     public RepositoryStatistics getLastStatistics( String repositoryId )
61     {
62         // TODO: consider a more efficient implementation that directly gets the last one from the content repository
63         List<String> scans = metadataRepository.getMetadataFacets( repositoryId, RepositoryStatistics.FACET_ID );
64         Collections.sort( scans );
65         if ( !scans.isEmpty() )
66         {
67             String name = scans.get( scans.size() - 1 );
68             return (RepositoryStatistics) metadataRepository.getMetadataFacet( repositoryId,
69                                                                                RepositoryStatistics.FACET_ID, name );
70         }
71         else
72         {
73             return null;
74         }
75     }
76
77     private void walkRepository( RepositoryStatistics stats, String repositoryId, String ns,
78                                  ManagedRepositoryContent repositoryContent )
79     {
80         for ( String namespace : metadataRepository.getNamespaces( repositoryId, ns ) )
81         {
82             walkRepository( stats, repositoryId, ns + "." + namespace, repositoryContent );
83         }
84
85         Collection<String> projects = metadataRepository.getProjects( repositoryId, ns );
86         if ( !projects.isEmpty() )
87         {
88             stats.setTotalGroupCount( stats.getTotalGroupCount() + 1 );
89             stats.setTotalProjectCount( stats.getTotalProjectCount() + projects.size() );
90
91             for ( String project : projects )
92             {
93                 for ( String version : metadataRepository.getProjectVersions( repositoryId, ns, project ) )
94                 {
95                     for ( ArtifactMetadata artifact : metadataRepository.getArtifacts( repositoryId, ns, project,
96                                                                                        version ) )
97                     {
98                         stats.setTotalArtifactCount( stats.getTotalArtifactCount() + 1 );
99                         stats.setTotalArtifactFileSize( stats.getTotalArtifactFileSize() + artifact.getSize() );
100
101                         // TODO: need a maven2 metadata repository API equivalent
102                         try
103                         {
104                             String type = repositoryContent.toArtifactReference(
105                                 ns.replace( '.', '/' ) + "/" + project + "/" + version + "/" +
106                                     artifact.getId() ).getType();
107                             stats.setTotalCountForType( type, stats.getTotalCountForType( type ) + 1 );
108                         }
109                         catch ( LayoutException e )
110                         {
111                             // ignore
112                         }
113                     }
114                 }
115             }
116         }
117     }
118
119
120     public void addStatisticsAfterScan( String repositoryId, Date startTime, Date endTime, long totalFiles,
121                                         long newFiles )
122     {
123         RepositoryStatistics repositoryStatistics = new RepositoryStatistics();
124         repositoryStatistics.setScanStartTime( startTime );
125         repositoryStatistics.setScanEndTime( endTime );
126         repositoryStatistics.setTotalFileCount( totalFiles );
127         repositoryStatistics.setNewFileCount( newFiles );
128
129         // In the future, instead of being tied to a scan we might want to record information in the fly based on
130         // events that are occurring. Even without these totals we could query much of the information on demand based
131         // on information from the metadata content repository. In the mean time, we lock information in at scan time.
132         // Note that if new types are later discoverable due to a code change or new plugin, historical stats will not
133         // be updated and the repository will need to be rescanned.
134
135         long startWalk = System.currentTimeMillis();
136         // TODO: we can probably get a more efficient implementation directly from the metadata repository, but for now
137         //       we just walk it. Alternatively, we could build an index, or store the aggregate information and update
138         //       it on the fly
139         for ( String ns : metadataRepository.getRootNamespaces( repositoryId ) )
140         {
141             ManagedRepositoryContent content;
142             try
143             {
144                 content = repositoryContentFactory.getManagedRepositoryContent( repositoryId );
145             }
146             catch ( RepositoryException e )
147             {
148                 throw new RuntimeException( e );
149             }
150             walkRepository( repositoryStatistics, repositoryId, ns, content );
151         }
152         log.info( "Repository walk for statistics executed in " + ( System.currentTimeMillis() - startWalk ) + "ms" );
153
154         metadataRepository.addMetadataFacet( repositoryId, repositoryStatistics );
155     }
156
157     public void deleteStatistics( String repositoryId )
158     {
159         metadataRepository.removeMetadataFacets( repositoryId, RepositoryStatistics.FACET_ID );
160     }
161
162     public List<RepositoryStatistics> getStatisticsInRange( String repositoryId, Date startTime, Date endTime )
163     {
164         List<RepositoryStatistics> results = new ArrayList<RepositoryStatistics>();
165         List<String> list = metadataRepository.getMetadataFacets( repositoryId, RepositoryStatistics.FACET_ID );
166         Collections.sort( list, Collections.reverseOrder() );
167         for ( String name : list )
168         {
169             try
170             {
171                 Date date = createNameFormat().parse( name );
172                 if ( ( startTime == null || !date.before( startTime ) ) &&
173                     ( endTime == null || !date.after( endTime ) ) )
174                 {
175                     RepositoryStatistics stats =
176                         (RepositoryStatistics) metadataRepository.getMetadataFacet( repositoryId,
177                                                                                     RepositoryStatistics.FACET_ID,
178                                                                                     name );
179                     results.add( stats );
180                 }
181             }
182             catch ( ParseException e )
183             {
184                 log.error( "Invalid scan result found in the metadata repository: " + e.getMessage() );
185                 // continue and ignore this one
186             }
187         }
188         return results;
189     }
190
191     private static SimpleDateFormat createNameFormat()
192     {
193         SimpleDateFormat fmt = new SimpleDateFormat( RepositoryStatistics.SCAN_TIMESTAMP_FORMAT );
194         fmt.setTimeZone( UTC_TIME_ZONE );
195         return fmt;
196     }
197
198     public void setMetadataRepository( MetadataRepository metadataRepository )
199     {
200         this.metadataRepository = metadataRepository;
201     }
202
203     public void setRepositoryContentFactory( RepositoryContentFactory repositoryContentFactory )
204     {
205         this.repositoryContentFactory = repositoryContentFactory;
206     }
207 }