]> source.dussan.org Git - archiva.git/blob
8fb3261046355c3a593fc8c2400362f9496c78dd
[archiva.git] /
1 package org.apache.archiva.metadata.repository.storage.maven2;
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.io.File;
23 import java.io.FilenameFilter;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.List;
29
30 import org.apache.archiva.metadata.model.ProjectMetadata;
31 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
32 import org.apache.archiva.metadata.model.ProjectVersionReference;
33 import org.apache.archiva.metadata.repository.MetadataResolverException;
34 import org.apache.archiva.metadata.repository.filter.AllFilter;
35 import org.apache.archiva.metadata.repository.filter.Filter;
36 import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
37 import org.apache.archiva.metadata.repository.storage.StorageMetadataResolver;
38 import org.apache.maven.archiva.common.utils.VersionUtil;
39 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
40 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
41 import org.apache.maven.archiva.xml.XMLException;
42 import org.apache.maven.model.CiManagement;
43 import org.apache.maven.model.Dependency;
44 import org.apache.maven.model.IssueManagement;
45 import org.apache.maven.model.License;
46 import org.apache.maven.model.MailingList;
47 import org.apache.maven.model.Model;
48 import org.apache.maven.model.Organization;
49 import org.apache.maven.model.Scm;
50 import org.apache.maven.model.building.DefaultModelBuildingRequest;
51 import org.apache.maven.model.building.ModelBuilder;
52 import org.apache.maven.model.building.ModelBuildingException;
53 import org.apache.maven.model.building.ModelBuildingRequest;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 /**
58  * @plexus.component role="org.apache.archiva.metadata.repository.storage.StorageMetadataResolver" role-hint="maven2"
59  */
60 public class Maven2RepositoryMetadataResolver
61     implements StorageMetadataResolver
62 {
63     /**
64      * @plexus.requirement
65      */
66     private ModelBuilder builder;
67
68     /**
69      * @plexus.requirement
70      */
71     private ArchivaConfiguration archivaConfiguration;
72
73     /**
74      * @plexus.requirement role-hint="maven2"
75      */
76     private RepositoryPathTranslator pathTranslator;
77
78     private final static Logger log = LoggerFactory.getLogger( Maven2RepositoryMetadataResolver.class );
79
80     private static final String METADATA_FILENAME = "maven-metadata.xml";
81
82     private static final Filter<String> ALL = new AllFilter<String>();
83
84     public ProjectMetadata getProject( String repoId, String namespace, String projectId )
85     {
86         // TODO: could natively implement the "shared model" concept from the browse action to avoid needing it there?
87         return null;
88     }
89
90     public ProjectVersionMetadata getProjectVersion( String repoId, String namespace, String projectId,
91                                                      String projectVersion )
92         throws MetadataResolverException
93     {
94         ManagedRepositoryConfiguration repositoryConfiguration =
95             archivaConfiguration.getConfiguration().findManagedRepositoryById( repoId );
96
97         String artifactVersion = projectVersion;
98
99         File basedir = new File( repositoryConfiguration.getLocation() );
100         if ( VersionUtil.isSnapshot( projectVersion ) )
101         {
102             File metadataFile =
103                 pathTranslator.toFile( basedir, namespace, projectId, projectVersion, METADATA_FILENAME );
104             try
105             {
106                 MavenRepositoryMetadata metadata = MavenRepositoryMetadataReader.read( metadataFile );
107
108                 // re-adjust to timestamp if present, otherwise retain the original -SNAPSHOT filename
109                 MavenRepositoryMetadata.Snapshot snapshotVersion = metadata.getSnapshotVersion();
110                 if ( snapshotVersion != null )
111                 {
112                     artifactVersion =
113                         artifactVersion.substring( 0, artifactVersion.length() - 8 ); // remove SNAPSHOT from end
114                     artifactVersion =
115                         artifactVersion + snapshotVersion.getTimestamp() + "-" + snapshotVersion.getBuildNumber();
116                 }
117             }
118             catch ( XMLException e )
119             {
120                 // unable to parse metadata - log it, and continue with the version as the original SNAPSHOT version
121                 log.warn( "Invalid metadata: " + metadataFile + " - " + e.getMessage() );
122             }
123         }
124
125         File file = pathTranslator.toFile( basedir, namespace, projectId, projectVersion,
126                                            projectId + "-" + artifactVersion + ".pom" );
127
128         if ( !file.exists() )
129         {
130             // metadata could not be resolved
131             return null;
132         }
133
134         ModelBuildingRequest req = new DefaultModelBuildingRequest();
135         req.setProcessPlugins( false );
136         req.setPomFile( file );
137         req.setModelResolver( new RepositoryModelResolver( basedir, pathTranslator ) );
138         req.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
139
140         Model model;
141         try
142         {
143             model = builder.build( req ).getEffectiveModel();
144         }
145         catch ( ModelBuildingException e )
146         {
147             throw new MetadataResolverException( "Unable to build Maven POM to derive metadata from: " + e.getMessage(),
148                                                  e );
149         }
150
151         ProjectVersionMetadata metadata = new ProjectVersionMetadata();
152         metadata.setCiManagement( convertCiManagement( model.getCiManagement() ) );
153         metadata.setDescription( model.getDescription() );
154         metadata.setId( projectVersion );
155         metadata.setIssueManagement( convertIssueManagement( model.getIssueManagement() ) );
156         metadata.setLicenses( convertLicenses( model.getLicenses() ) );
157         metadata.setMailingLists( convertMailingLists( model.getMailingLists() ) );
158         metadata.setDependencies( convertDependencies( model.getDependencies() ) );
159         metadata.setName( model.getName() );
160         metadata.setOrganization( convertOrganization( model.getOrganization() ) );
161         metadata.setScm( convertScm( model.getScm() ) );
162         metadata.setUrl( model.getUrl() );
163
164         MavenProjectFacet facet = new MavenProjectFacet();
165         facet.setGroupId( model.getGroupId() != null ? model.getGroupId() : model.getParent().getGroupId() );
166         facet.setArtifactId( model.getArtifactId() );
167         facet.setPackaging( model.getPackaging() );
168         if ( model.getParent() != null )
169         {
170             MavenProjectParent parent = new MavenProjectParent();
171             parent.setGroupId( model.getParent().getGroupId() );
172             parent.setArtifactId( model.getParent().getArtifactId() );
173             parent.setVersion( model.getParent().getVersion() );
174             facet.setParent( parent );
175         }
176         metadata.addFacet( facet );
177
178         return metadata;
179     }
180
181     private List<org.apache.archiva.metadata.model.Dependency> convertDependencies( List<Dependency> dependencies )
182     {
183         List<org.apache.archiva.metadata.model.Dependency> l =
184             new ArrayList<org.apache.archiva.metadata.model.Dependency>();
185         for ( Dependency dependency : dependencies )
186         {
187             org.apache.archiva.metadata.model.Dependency newDependency =
188                 new org.apache.archiva.metadata.model.Dependency();
189             newDependency.setArtifactId( dependency.getArtifactId() );
190             newDependency.setClassifier( dependency.getClassifier() );
191             newDependency.setGroupId( dependency.getGroupId() );
192             newDependency.setOptional( dependency.isOptional() );
193             newDependency.setScope( dependency.getScope() );
194             newDependency.setSystemPath( dependency.getSystemPath() );
195             newDependency.setType( dependency.getType() );
196             newDependency.setVersion( dependency.getVersion() );
197             l.add( newDependency );
198         }
199         return l;
200     }
201
202     private org.apache.archiva.metadata.model.Scm convertScm( Scm scm )
203     {
204         org.apache.archiva.metadata.model.Scm newScm = null;
205         if ( scm != null )
206         {
207             newScm = new org.apache.archiva.metadata.model.Scm();
208             newScm.setConnection( scm.getConnection() );
209             newScm.setDeveloperConnection( scm.getDeveloperConnection() );
210             newScm.setUrl( scm.getUrl() );
211         }
212         return newScm;
213     }
214
215     private org.apache.archiva.metadata.model.Organization convertOrganization( Organization organization )
216     {
217         org.apache.archiva.metadata.model.Organization org = null;
218         if ( organization != null )
219         {
220             org = new org.apache.archiva.metadata.model.Organization();
221             org.setName( organization.getName() );
222             org.setUrl( organization.getUrl() );
223         }
224         return org;
225     }
226
227     private List<org.apache.archiva.metadata.model.License> convertLicenses( List<License> licenses )
228     {
229         List<org.apache.archiva.metadata.model.License> l = new ArrayList<org.apache.archiva.metadata.model.License>();
230         for ( License license : licenses )
231         {
232             org.apache.archiva.metadata.model.License newLicense = new org.apache.archiva.metadata.model.License();
233             newLicense.setName( license.getName() );
234             newLicense.setUrl( license.getUrl() );
235             l.add( newLicense );
236         }
237         return l;
238     }
239
240     private List<org.apache.archiva.metadata.model.MailingList> convertMailingLists( List<MailingList> mailingLists )
241     {
242         List<org.apache.archiva.metadata.model.MailingList> l =
243             new ArrayList<org.apache.archiva.metadata.model.MailingList>();
244         for ( MailingList mailingList : mailingLists )
245         {
246             org.apache.archiva.metadata.model.MailingList newMailingList =
247                 new org.apache.archiva.metadata.model.MailingList();
248             newMailingList.setName( mailingList.getName() );
249             newMailingList.setMainArchiveUrl( mailingList.getArchive() );
250             newMailingList.setPostAddress( mailingList.getPost() );
251             newMailingList.setSubscribeAddress( mailingList.getSubscribe() );
252             newMailingList.setUnsubscribeAddress( mailingList.getUnsubscribe() );
253             newMailingList.setOtherArchives( mailingList.getOtherArchives() );
254             l.add( newMailingList );
255         }
256         return l;
257     }
258
259     private org.apache.archiva.metadata.model.IssueManagement convertIssueManagement( IssueManagement issueManagement )
260     {
261         org.apache.archiva.metadata.model.IssueManagement im = null;
262         if ( issueManagement != null )
263         {
264             im = new org.apache.archiva.metadata.model.IssueManagement();
265             im.setSystem( issueManagement.getSystem() );
266             im.setUrl( issueManagement.getUrl() );
267         }
268         return im;
269     }
270
271     private org.apache.archiva.metadata.model.CiManagement convertCiManagement( CiManagement ciManagement )
272     {
273         org.apache.archiva.metadata.model.CiManagement ci = null;
274         if ( ciManagement != null )
275         {
276             ci = new org.apache.archiva.metadata.model.CiManagement();
277             ci.setSystem( ciManagement.getSystem() );
278             ci.setUrl( ciManagement.getUrl() );
279         }
280         return ci;
281     }
282
283     public Collection<String> getArtifactVersions( String repoId, String namespace, String projectId,
284                                                    String projectVersion )
285     {
286         // TODO: useful, but not implemented yet, not called from DefaultMetadataResolver
287         throw new UnsupportedOperationException();
288     }
289
290     public Collection<ProjectVersionReference> getProjectReferences( String repoId, String namespace, String projectId,
291                                                                      String projectVersion )
292     {
293         // Can't be determined on a Maven 2 repository
294         throw new UnsupportedOperationException();
295     }
296
297     public Collection<String> getRootNamespaces( String repoId )
298     {
299         return getRootNamespaces( repoId, ALL );
300     }
301
302     public Collection<String> getRootNamespaces( String repoId, Filter<String> filter )
303     {
304         File dir = getRepositoryBasedir( repoId );
305
306         String[] files = dir.list( new DirectoryFilter( filter ) );
307         return files != null ? Arrays.asList( files ) : Collections.<String>emptyList();
308     }
309
310     private File getRepositoryBasedir( String repoId )
311     {
312         ManagedRepositoryConfiguration repositoryConfiguration =
313             archivaConfiguration.getConfiguration().findManagedRepositoryById( repoId );
314
315         return new File( repositoryConfiguration.getLocation() );
316     }
317
318     public Collection<String> getNamespaces( String repoId, String namespace )
319     {
320         return getNamespaces( repoId, namespace, ALL );
321     }
322
323     public Collection<String> getNamespaces( String repoId, String namespace, Filter<String> filter )
324     {
325         File dir = pathTranslator.toFile( getRepositoryBasedir( repoId ), namespace );
326
327         // scan all the directories which are potential namespaces. Any directories known to be projects are excluded
328         Collection<String> namespaces = new ArrayList<String>();
329         File[] files = dir.listFiles( new DirectoryFilter( filter ) );
330         if ( files != null )
331         {
332             for ( File file : files )
333             {
334                 if ( !isProject( file, filter ) )
335                 {
336                     namespaces.add( file.getName() );
337                 }
338             }
339         }
340         return namespaces;
341     }
342
343     public Collection<String> getProjects( String repoId, String namespace )
344     {
345         return getProjects( repoId, namespace, ALL );
346     }
347
348     public Collection<String> getProjects( String repoId, String namespace, Filter<String> filter )
349     {
350         File dir = pathTranslator.toFile( getRepositoryBasedir( repoId ), namespace );
351
352         // scan all directories in the namespace, and only include those that are known to be projects
353         Collection<String> projects = new ArrayList<String>();
354         File[] files = dir.listFiles( new DirectoryFilter( filter ) );
355         if ( files != null )
356         {
357             for ( File file : files )
358             {
359                 if ( isProject( file, filter ) )
360                 {
361                     projects.add( file.getName() );
362                 }
363             }
364         }
365         return projects;
366     }
367
368     public Collection<String> getProjectVersions( String repoId, String namespace, String projectId )
369     {
370         return getProjectVersions( repoId, namespace, projectId, ALL );
371     }
372
373     public Collection<String> getProjectVersions( String repoId, String namespace, String projectId,
374                                                   Filter<String> filter )
375     {
376         File dir = pathTranslator.toFile( getRepositoryBasedir( repoId ), namespace, projectId );
377
378         // all directories in a project directory can be considered a version
379         String[] files = dir.list( new DirectoryFilter( filter ) );
380         return files != null ? Arrays.asList( files ) : Collections.<String>emptyList();
381     }
382
383     private boolean isProject( File dir, Filter<String> filter )
384     {
385         // scan directories for a valid project version subdirectory, meaning this must be a project directory
386         File[] files = dir.listFiles( new DirectoryFilter( filter ) );
387         if ( files != null )
388         {
389             for ( File file : files )
390             {
391                 if ( isProjectVersion( file ) )
392                 {
393                     return true;
394                 }
395             }
396         }
397
398         // if a metadata file is present, check if this is the "artifactId" directory, marking it as a project
399         MavenRepositoryMetadata metadata = readMetadata( dir );
400         if ( metadata != null && dir.getName().equals( metadata.getArtifactId() ) )
401         {
402             return true;
403         }
404
405         return false;
406     }
407
408     private boolean isProjectVersion( File dir )
409     {
410         final String artifactId = dir.getParentFile().getName();
411         final String projectVersion = dir.getName();
412
413         // check if there is a POM artifact file to ensure it is a version directory
414         File[] files;
415         if ( VersionUtil.isSnapshot( projectVersion ) )
416         {
417             files = dir.listFiles( new FilenameFilter()
418             {
419                 public boolean accept( File dir, String name )
420                 {
421                     if ( name.startsWith( artifactId + "-" ) && name.endsWith( ".pom" ) )
422                     {
423                         String v = name.substring( artifactId.length() + 1, name.length() - 4 );
424                         v = VersionUtil.getBaseVersion( v );
425                         if ( v.equals( projectVersion ) )
426                         {
427                             return true;
428                         }
429                     }
430                     return false;
431                 }
432             } );
433         }
434         else
435         {
436             final String pomFile = artifactId + "-" + projectVersion + ".pom";
437             files = dir.listFiles( new FilenameFilter()
438             {
439                 public boolean accept( File dir, String name )
440                 {
441                     return pomFile.equals( name );
442                 }
443             } );
444         }
445         if ( files != null && files.length > 0 )
446         {
447             return true;
448         }
449
450         // if a metadata file is present, check if this is the "version" directory, marking it as a project version
451         MavenRepositoryMetadata metadata = readMetadata( dir );
452         if ( metadata != null && projectVersion.equals( metadata.getVersion() ) )
453         {
454             return true;
455         }
456
457         return false;
458     }
459
460     private MavenRepositoryMetadata readMetadata( File directory )
461     {
462         MavenRepositoryMetadata metadata = null;
463         File metadataFile = new File( directory, METADATA_FILENAME );
464         if ( metadataFile.exists() )
465         {
466             try
467             {
468                 metadata = MavenRepositoryMetadataReader.read( metadataFile );
469             }
470             catch ( XMLException e )
471             {
472                 // ignore missing or invalid metadata
473             }
474         }
475         return metadata;
476     }
477
478     private static class DirectoryFilter
479         implements FilenameFilter
480     {
481         private final Filter<String> filter;
482
483         public DirectoryFilter( Filter<String> filter )
484         {
485             this.filter = filter;
486         }
487
488         public boolean accept( File dir, String name )
489         {
490             if ( !filter.accept( name ) )
491             {
492                 return false;
493             }
494             else if ( name.startsWith( "." ) )
495             {
496                 return false;
497             }
498             else if ( !new File( dir, name ).isDirectory() )
499             {
500                 return false;
501             }
502             return true;
503         }
504     }
505 }