]> source.dussan.org Git - archiva.git/blob
d493158b8cafc953e51d1db9844759d00cd2f753
[archiva.git] /
1 package org.apache.maven.archiva.reporting;
2
3 /*
4  * Copyright 2005-2006 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 import org.apache.maven.archiva.layer.RepositoryQueryLayer;
20 import org.apache.maven.archiva.layer.RepositoryQueryLayerFactory;
21 import org.apache.maven.artifact.Artifact;
22 import org.apache.maven.artifact.factory.ArtifactFactory;
23 import org.apache.maven.artifact.repository.ArtifactRepository;
24 import org.apache.maven.artifact.repository.metadata.Plugin;
25 import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
26 import org.apache.maven.artifact.repository.metadata.Snapshot;
27 import org.apache.maven.artifact.repository.metadata.Versioning;
28 import org.codehaus.plexus.util.FileUtils;
29 import org.codehaus.plexus.util.StringUtils;
30
31 import java.io.File;
32 import java.io.IOException;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.Collections;
36 import java.util.HashMap;
37 import java.util.Iterator;
38 import java.util.List;
39 import java.util.Map;
40
41 /**
42  * This class will report on bad metadata files.  These include invalid version declarations and incomplete version
43  * information inside the metadata file.  Plugin metadata will be checked for validity of the latest plugin artifacts.
44  *
45  * @plexus.component role="org.apache.maven.archiva.reporting.MetadataReportProcessor" role-hint="bad-metadata"
46  */
47 public class BadMetadataReportProcessor
48     implements MetadataReportProcessor
49 {
50     /**
51      * @plexus.requirement
52      */
53     private ArtifactFactory artifactFactory;
54
55     /**
56      * @plexus.requirement
57      */
58     private RepositoryQueryLayerFactory repositoryQueryLayerFactory;
59
60     private static final String ROLE_HINT = "bad-metadata";
61
62     /**
63      * Process the metadata encountered in the repository and report all errors found, if any.
64      *
65      * @param metadata   the metadata to be processed.
66      * @param repository the repository where the metadata was encountered
67      * @param reporter   the ReportingDatabase to receive processing results
68      */
69     public void processMetadata( RepositoryMetadata metadata, ArtifactRepository repository,
70                                  ReportingDatabase reporter )
71     {
72         if ( metadata.storedInGroupDirectory() )
73         {
74             try
75             {
76                 checkPluginMetadata( metadata, repository, reporter );
77             }
78             catch ( IOException e )
79             {
80                 addWarning( reporter, metadata, null, "Error getting plugin artifact directories versions: " + e );
81             }
82         }
83         else
84         {
85             Versioning versioning = metadata.getMetadata().getVersioning();
86             boolean found = false;
87             if ( versioning != null )
88             {
89                 String lastUpdated = versioning.getLastUpdated();
90                 if ( lastUpdated != null && lastUpdated.length() != 0 )
91                 {
92                     found = true;
93                 }
94             }
95             if ( !found )
96             {
97                 addFailure( reporter, metadata, "missing-last-updated",
98                             "Missing lastUpdated element inside the metadata." );
99             }
100
101             if ( metadata.storedInArtifactVersionDirectory() )
102             {
103                 checkSnapshotMetadata( metadata, repository, reporter );
104             }
105             else
106             {
107                 checkMetadataVersions( metadata, repository, reporter );
108
109                 try
110                 {
111                     checkRepositoryVersions( metadata, repository, reporter );
112                 }
113                 catch ( IOException e )
114                 {
115                     String reason = "Error getting plugin artifact directories versions: " + e;
116                     addWarning( reporter, metadata, null, reason );
117                 }
118             }
119         }
120     }
121
122     private static void addWarning( ReportingDatabase reporter, RepositoryMetadata metadata, String problem,
123                                     String reason )
124     {
125         // TODO: reason could be an i18n key derived from the processor and the problem ID and the
126         reporter.addWarning( metadata, ROLE_HINT, problem, reason );
127     }
128
129     /**
130      * Method for processing a GroupRepositoryMetadata
131      *
132      * @param metadata   the metadata to be processed.
133      * @param repository the repository where the metadata was encountered
134      * @param reporter   the ReportingDatabase to receive processing results
135      */
136     private void checkPluginMetadata( RepositoryMetadata metadata, ArtifactRepository repository,
137                                       ReportingDatabase reporter )
138         throws IOException
139     {
140         File metadataDir =
141             new File( repository.getBasedir(), repository.pathOfRemoteRepositoryMetadata( metadata ) ).getParentFile();
142         List pluginDirs = getArtifactIdFiles( metadataDir );
143
144         Map prefixes = new HashMap();
145         for ( Iterator plugins = metadata.getMetadata().getPlugins().iterator(); plugins.hasNext(); )
146         {
147             Plugin plugin = (Plugin) plugins.next();
148
149             String artifactId = plugin.getArtifactId();
150             if ( artifactId == null || artifactId.length() == 0 )
151             {
152                 addFailure( reporter, metadata, "missing-artifact-id:" + plugin.getPrefix(),
153                             "Missing or empty artifactId in group metadata for plugin " + plugin.getPrefix() );
154             }
155
156             String prefix = plugin.getPrefix();
157             if ( prefix == null || prefix.length() == 0 )
158             {
159                 addFailure( reporter, metadata, "missing-plugin-prefix:" + artifactId,
160                             "Missing or empty plugin prefix for artifactId " + artifactId + "." );
161             }
162             else
163             {
164                 if ( prefixes.containsKey( prefix ) )
165                 {
166                     addFailure( reporter, metadata, "duplicate-plugin-prefix:" + prefix,
167                                 "Duplicate plugin prefix found: " + prefix + "." );
168                 }
169                 else
170                 {
171                     prefixes.put( prefix, plugin );
172                 }
173             }
174
175             if ( artifactId != null && artifactId.length() > 0 )
176             {
177                 File pluginDir = new File( metadataDir, artifactId );
178                 if ( !pluginDirs.contains( pluginDir ) )
179                 {
180                     addFailure( reporter, metadata, "missing-plugin-from-repository:" + artifactId,
181                                 "Metadata plugin " + artifactId + " not found in the repository" );
182                 }
183                 else
184                 {
185                     pluginDirs.remove( pluginDir );
186                 }
187             }
188         }
189
190         if ( pluginDirs.size() > 0 )
191         {
192             for ( Iterator plugins = pluginDirs.iterator(); plugins.hasNext(); )
193             {
194                 File plugin = (File) plugins.next();
195                 addFailure( reporter, metadata, "missing-plugin-from-metadata:" + plugin.getName(), "Plugin " +
196                     plugin.getName() + " is present in the repository but " + "missing in the metadata." );
197             }
198         }
199     }
200
201     /**
202      * Method for processing a SnapshotArtifactRepository
203      *
204      * @param metadata   the metadata to be processed.
205      * @param repository the repository where the metadata was encountered
206      * @param reporter   the ReportingDatabase to receive processing results
207      */
208     private void checkSnapshotMetadata( RepositoryMetadata metadata, ArtifactRepository repository,
209                                         ReportingDatabase reporter )
210     {
211         RepositoryQueryLayer repositoryQueryLayer =
212             repositoryQueryLayerFactory.createRepositoryQueryLayer( repository );
213
214         Versioning versioning = metadata.getMetadata().getVersioning();
215         if ( versioning != null )
216         {
217             Snapshot snapshot = versioning.getSnapshot();
218
219             String version = StringUtils.replace( metadata.getBaseVersion(), Artifact.SNAPSHOT_VERSION,
220                                                   snapshot.getTimestamp() + "-" + snapshot.getBuildNumber() );
221             Artifact artifact =
222                 artifactFactory.createProjectArtifact( metadata.getGroupId(), metadata.getArtifactId(), version );
223             artifact.isSnapshot(); // trigger baseVersion correction
224
225             if ( !repositoryQueryLayer.containsArtifact( artifact ) )
226             {
227                 addFailure( reporter, metadata, "missing-snapshot-artifact-from-repository:" + version,
228                             "Snapshot artifact " + version + " does not exist." );
229             }
230         }
231     }
232
233     /**
234      * Method for validating the versions declared inside an ArtifactRepositoryMetadata
235      *
236      * @param metadata   the metadata to be processed.
237      * @param repository the repository where the metadata was encountered
238      * @param reporter   the ReportingDatabase to receive processing results
239      */
240     private void checkMetadataVersions( RepositoryMetadata metadata, ArtifactRepository repository,
241                                         ReportingDatabase reporter )
242     {
243         RepositoryQueryLayer repositoryQueryLayer =
244             repositoryQueryLayerFactory.createRepositoryQueryLayer( repository );
245
246         Versioning versioning = metadata.getMetadata().getVersioning();
247         if ( versioning != null )
248         {
249             for ( Iterator versions = versioning.getVersions().iterator(); versions.hasNext(); )
250             {
251                 String version = (String) versions.next();
252
253                 Artifact artifact =
254                     artifactFactory.createProjectArtifact( metadata.getGroupId(), metadata.getArtifactId(), version );
255
256                 if ( !repositoryQueryLayer.containsArtifact( artifact ) )
257                 {
258                     addFailure( reporter, metadata, "missing-artifact-from-repository:" + version, "Artifact version " +
259                         version + " is present in metadata but " + "missing in the repository." );
260                 }
261             }
262         }
263     }
264
265     /**
266      * Searches the artifact repository directory for all versions and verifies that all of them are listed in the
267      * ArtifactRepositoryMetadata
268      *
269      * @param metadata   the metadata to be processed.
270      * @param repository the repository where the metadata was encountered
271      * @param reporter   the ReportingDatabase to receive processing results
272      * @throws java.io.IOException if there is a problem reading from the file system
273      */
274     private void checkRepositoryVersions( RepositoryMetadata metadata, ArtifactRepository repository,
275                                           ReportingDatabase reporter )
276         throws IOException
277     {
278         Versioning versioning = metadata.getMetadata().getVersioning();
279         List metadataVersions = versioning != null ? versioning.getVersions() : Collections.EMPTY_LIST;
280         File versionsDir =
281             new File( repository.getBasedir(), repository.pathOfRemoteRepositoryMetadata( metadata ) ).getParentFile();
282
283         // TODO: I don't know how this condition can happen, but it was seen on the main repository.
284         // Avoid hard failure
285         if ( versionsDir.exists() )
286         {
287             List versions = FileUtils.getFileNames( versionsDir, "*/*.pom", null, false );
288             for ( Iterator i = versions.iterator(); i.hasNext(); )
289             {
290                 File path = new File( (String) i.next() );
291                 String version = path.getParentFile().getName();
292                 if ( !metadataVersions.contains( version ) )
293                 {
294                     addFailure( reporter, metadata, "missing-artifact-from-metadata:" + version, "Artifact version " +
295                         version + " found in the repository but " + "missing in the metadata." );
296                 }
297             }
298         }
299         else
300         {
301             addFailure( reporter, metadata, null, "Metadata's directory did not exist: " + versionsDir );
302         }
303     }
304
305     /**
306      * Used to gather artifactIds from a groupId directory.
307      *
308      * @param groupIdDir the directory of the group
309      * @return the list of artifact ID File objects for each directory
310      * @throws IOException if there was a failure to read the directories
311      */
312     private List getArtifactIdFiles( File groupIdDir )
313         throws IOException
314     {
315         List artifactIdFiles = new ArrayList();
316
317         File[] files = groupIdDir.listFiles();
318         if ( files != null )
319         {
320             for ( Iterator i = Arrays.asList( files ).iterator(); i.hasNext(); )
321             {
322                 File artifactDir = (File) i.next();
323
324                 if ( artifactDir.isDirectory() )
325                 {
326                     List versions = FileUtils.getFileNames( artifactDir, "*/*.pom", null, false );
327                     if ( versions.size() > 0 )
328                     {
329                         artifactIdFiles.add( artifactDir );
330                     }
331                 }
332             }
333         }
334
335         return artifactIdFiles;
336     }
337
338     private static void addFailure( ReportingDatabase reporter, RepositoryMetadata metadata, String problem,
339                                     String reason )
340     {
341         // TODO: reason could be an i18n key derived from the processor and the problem ID and the
342         reporter.addFailure( metadata, ROLE_HINT, problem, reason );
343     }
344 }