]> source.dussan.org Git - archiva.git/blob
d84b6eec524a746d2a5b88ed4b3e336ca68700c5
[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 org.apache.archiva.admin.model.RepositoryAdminException;
23 import org.apache.archiva.admin.model.beans.ManagedRepository;
24 import org.apache.archiva.admin.model.beans.NetworkProxy;
25 import org.apache.archiva.admin.model.beans.ProxyConnector;
26 import org.apache.archiva.admin.model.beans.RemoteRepository;
27 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
28 import org.apache.archiva.admin.model.networkproxy.NetworkProxyAdmin;
29 import org.apache.archiva.admin.model.proxyconnector.ProxyConnectorAdmin;
30 import org.apache.archiva.admin.model.remote.RemoteRepositoryAdmin;
31 import org.apache.archiva.checksum.ChecksumAlgorithm;
32 import org.apache.archiva.checksum.ChecksummedFile;
33 import org.apache.archiva.common.utils.VersionUtil;
34 import org.apache.archiva.metadata.model.ArtifactMetadata;
35 import org.apache.archiva.metadata.model.ProjectMetadata;
36 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
37 import org.apache.archiva.metadata.repository.filter.Filter;
38 import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
39 import org.apache.archiva.metadata.repository.storage.RepositoryStorage;
40 import org.apache.archiva.metadata.repository.storage.RepositoryStorageMetadataInvalidException;
41 import org.apache.archiva.metadata.repository.storage.RepositoryStorageMetadataNotFoundException;
42 import org.apache.archiva.proxy.common.WagonFactory;
43 import org.apache.archiva.reports.RepositoryProblemFacet;
44 import org.apache.archiva.xml.XMLException;
45 import org.apache.maven.model.CiManagement;
46 import org.apache.maven.model.Dependency;
47 import org.apache.maven.model.IssueManagement;
48 import org.apache.maven.model.License;
49 import org.apache.maven.model.MailingList;
50 import org.apache.maven.model.Model;
51 import org.apache.maven.model.Organization;
52 import org.apache.maven.model.Scm;
53 import org.apache.maven.model.building.DefaultModelBuilderFactory;
54 import org.apache.maven.model.building.DefaultModelBuildingRequest;
55 import org.apache.maven.model.building.ModelBuilder;
56 import org.apache.maven.model.building.ModelBuildingException;
57 import org.apache.maven.model.building.ModelBuildingRequest;
58 import org.apache.maven.model.building.ModelProblem;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61 import org.springframework.stereotype.Service;
62
63 import javax.annotation.PostConstruct;
64 import javax.inject.Inject;
65 import javax.inject.Named;
66 import java.io.File;
67 import java.io.FileNotFoundException;
68 import java.io.FilenameFilter;
69 import java.io.IOException;
70 import java.util.ArrayList;
71 import java.util.Arrays;
72 import java.util.Collection;
73 import java.util.Collections;
74 import java.util.Date;
75 import java.util.HashMap;
76 import java.util.List;
77 import java.util.Map;
78
79 /**
80  * Maven 2 repository format storage implementation. This class currently takes parameters to indicate the repository to
81  * deal with rather than being instantiated per-repository.
82  * FIXME: instantiate one per repository and allocate permanently from a factory (which can be obtained within the session).
83  * TODO: finish Maven 1 implementation to prove this API
84  * <p/>
85  * The session is passed in as an argument to obtain any necessary resources, rather than the class being instantiated
86  * within the session in the context of a single managed repository's resolution needs.
87  * <p/>
88  */
89 @Service( "repositoryStorage#maven2" )
90 public class Maven2RepositoryStorage
91     implements RepositoryStorage
92 {
93     /**
94      *
95      */
96     private ModelBuilder builder;
97
98     /**
99      *
100      */
101     @Inject
102     private RemoteRepositoryAdmin remoteRepositoryAdmin;
103
104     @Inject
105     private ManagedRepositoryAdmin managedRepositoryAdmin;
106
107     @Inject
108     private ProxyConnectorAdmin proxyConnectorAdmin;
109
110     @Inject
111     private NetworkProxyAdmin networkProxyAdmin;
112
113     /**
114      *
115      */
116     @Inject
117     @Named( value = "repositoryPathTranslator#maven2" )
118     private RepositoryPathTranslator pathTranslator;
119
120     @Inject
121     private WagonFactory wagonFactory;
122
123     private final static Logger log = LoggerFactory.getLogger( Maven2RepositoryStorage.class );
124
125     private static final String METADATA_FILENAME = "maven-metadata.xml";
126
127
128     @PostConstruct
129     public void initialize()
130     {
131         DefaultModelBuilderFactory defaultModelBuilderFactory = new DefaultModelBuilderFactory();
132         builder = defaultModelBuilderFactory.newInstance();
133     }
134
135     public ProjectMetadata readProjectMetadata( String repoId, String namespace, String projectId )
136     {
137         // TODO: could natively implement the "shared model" concept from the browse action to avoid needing it there?
138         return null;
139     }
140
141     public ProjectVersionMetadata readProjectVersionMetadata( String repoId, String namespace, String projectId,
142                                                               String projectVersion )
143         throws RepositoryStorageMetadataNotFoundException, RepositoryStorageMetadataInvalidException,
144         RepositoryAdminException
145     {
146
147         ManagedRepository repositoryConfiguration = managedRepositoryAdmin.getManagedRepository( repoId );
148
149         String artifactVersion = projectVersion;
150
151         File basedir = new File( repositoryConfiguration.getLocation() );
152         if ( VersionUtil.isSnapshot( projectVersion ) )
153         {
154             File metadataFile =
155                 pathTranslator.toFile( basedir, namespace, projectId, projectVersion, METADATA_FILENAME );
156             try
157             {
158                 MavenRepositoryMetadata metadata = MavenRepositoryMetadataReader.read( metadataFile );
159
160                 // re-adjust to timestamp if present, otherwise retain the original -SNAPSHOT filename
161                 MavenRepositoryMetadata.Snapshot snapshotVersion = metadata.getSnapshotVersion();
162                 if ( snapshotVersion != null )
163                 {
164                     artifactVersion =
165                         artifactVersion.substring( 0, artifactVersion.length() - 8 ); // remove SNAPSHOT from end
166                     artifactVersion =
167                         artifactVersion + snapshotVersion.getTimestamp() + "-" + snapshotVersion.getBuildNumber();
168                 }
169             }
170             catch ( XMLException e )
171             {
172                 // unable to parse metadata - log it, and continue with the version as the original SNAPSHOT version
173                 log.warn( "Invalid metadata: " + metadataFile + " - " + e.getMessage() );
174             }
175         }
176
177         // TODO: won't work well with some other layouts, might need to convert artifact parts to ID by path translator
178         String id = projectId + "-" + artifactVersion + ".pom";
179         File file = pathTranslator.toFile( basedir, namespace, projectId, projectVersion, id );
180
181         if ( !file.exists() )
182         {
183             // metadata could not be resolved
184             throw new RepositoryStorageMetadataNotFoundException(
185                 "The artifact's POM file '" + file.getAbsolutePath() + "' was missing" );
186         }
187
188         // TODO: this is a workaround until we can properly resolve using proxies as well - this doesn't cache
189         //       anything locally!
190         List<RemoteRepository> remoteRepositories = new ArrayList<RemoteRepository>();
191         Map<String, NetworkProxy> networkProxies = new HashMap<String, NetworkProxy>();
192
193         Map<String, List<ProxyConnector>> proxyConnectorsMap = proxyConnectorAdmin.getProxyConnectorAsMap();
194         List<ProxyConnector> proxyConnectors = proxyConnectorsMap.get( repoId );
195         if ( proxyConnectors != null )
196         {
197             for ( ProxyConnector proxyConnector : proxyConnectors )
198             {
199                 RemoteRepository remoteRepoConfig =
200                     remoteRepositoryAdmin.getRemoteRepository( proxyConnector.getTargetRepoId() );
201
202                 if ( remoteRepoConfig != null )
203                 {
204                     remoteRepositories.add( remoteRepoConfig );
205
206                     NetworkProxy networkProxyConfig = networkProxyAdmin.getNetworkProxy( proxyConnector.getProxyId() );
207
208                     if ( networkProxyConfig != null )
209                     {
210                         // key/value: remote repo ID/proxy info
211                         networkProxies.put( proxyConnector.getTargetRepoId(), networkProxyConfig );
212                     }
213                 }
214             }
215         }
216
217         ModelBuildingRequest req = new DefaultModelBuildingRequest();
218         req.setProcessPlugins( false );
219         req.setPomFile( file );
220
221         // MRM-1411
222         req.setModelResolver(
223             new RepositoryModelResolver( basedir, pathTranslator, wagonFactory, remoteRepositories, networkProxies,
224                                          repositoryConfiguration ) );
225         req.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
226
227         Model model;
228         try
229         {
230             model = builder.build( req ).getEffectiveModel();
231         }
232         catch ( ModelBuildingException e )
233         {
234             String msg = "The artifact's POM file '" + file + "' was invalid: " + e.getMessage();
235
236             List<ModelProblem> modelProblems = e.getProblems();
237             for ( ModelProblem problem : modelProblems )
238             {
239                 // MRM-1411, related to MRM-1335
240                 // this means that the problem was that the parent wasn't resolved!
241                 if ( problem.getException() instanceof FileNotFoundException && e.getModelId() != null &&
242                     !e.getModelId().equals( problem.getModelId() ) )
243                 {
244                     log.warn( "The artifact's parent POM file '" + file + "' cannot be resolved. " +
245                                   "Using defaults for project version metadata.." );
246
247                     ProjectVersionMetadata metadata = new ProjectVersionMetadata();
248                     metadata.setId( projectVersion );
249
250                     MavenProjectFacet facet = new MavenProjectFacet();
251                     facet.setGroupId( namespace );
252                     facet.setArtifactId( projectId );
253                     facet.setPackaging( "jar" );
254                     metadata.addFacet( facet );
255
256                     String errMsg =
257                         "Error in resolving artifact's parent POM file. " + problem.getException().getMessage();
258                     RepositoryProblemFacet repoProblemFacet = new RepositoryProblemFacet();
259                     repoProblemFacet.setRepositoryId( repoId );
260                     repoProblemFacet.setId( repoId );
261                     repoProblemFacet.setMessage( errMsg );
262                     repoProblemFacet.setProblem( errMsg );
263                     repoProblemFacet.setProject( projectId );
264                     repoProblemFacet.setVersion( projectVersion );
265                     repoProblemFacet.setNamespace( namespace );
266
267                     metadata.addFacet( repoProblemFacet );
268
269                     return metadata;
270                 }
271             }
272
273             throw new RepositoryStorageMetadataInvalidException( "invalid-pom", msg, e );
274         }
275
276         // Check if the POM is in the correct location
277         boolean correctGroupId = namespace.equals( model.getGroupId() );
278         boolean correctArtifactId = projectId.equals( model.getArtifactId() );
279         boolean correctVersion = projectVersion.equals( model.getVersion() );
280         if ( !correctGroupId || !correctArtifactId || !correctVersion )
281         {
282             StringBuilder message = new StringBuilder( "Incorrect POM coordinates in '" + file + "':" );
283             if ( !correctGroupId )
284             {
285                 message.append( "\nIncorrect group ID: " ).append( model.getGroupId() );
286             }
287             if ( !correctArtifactId )
288             {
289                 message.append( "\nIncorrect artifact ID: " ).append( model.getArtifactId() );
290             }
291             if ( !correctVersion )
292             {
293                 message.append( "\nIncorrect version: " ).append( model.getVersion() );
294             }
295
296             throw new RepositoryStorageMetadataInvalidException( "mislocated-pom", message.toString() );
297         }
298
299         ProjectVersionMetadata metadata = new ProjectVersionMetadata();
300         metadata.setCiManagement( convertCiManagement( model.getCiManagement() ) );
301         metadata.setDescription( model.getDescription() );
302         metadata.setId( projectVersion );
303         metadata.setIssueManagement( convertIssueManagement( model.getIssueManagement() ) );
304         metadata.setLicenses( convertLicenses( model.getLicenses() ) );
305         metadata.setMailingLists( convertMailingLists( model.getMailingLists() ) );
306         metadata.setDependencies( convertDependencies( model.getDependencies() ) );
307         metadata.setName( model.getName() );
308         metadata.setOrganization( convertOrganization( model.getOrganization() ) );
309         metadata.setScm( convertScm( model.getScm() ) );
310         metadata.setUrl( model.getUrl() );
311
312         MavenProjectFacet facet = new MavenProjectFacet();
313         facet.setGroupId( model.getGroupId() != null ? model.getGroupId() : model.getParent().getGroupId() );
314         facet.setArtifactId( model.getArtifactId() );
315         facet.setPackaging( model.getPackaging() );
316         if ( model.getParent() != null )
317         {
318             MavenProjectParent parent = new MavenProjectParent();
319             parent.setGroupId( model.getParent().getGroupId() );
320             parent.setArtifactId( model.getParent().getArtifactId() );
321             parent.setVersion( model.getParent().getVersion() );
322             facet.setParent( parent );
323         }
324         metadata.addFacet( facet );
325
326         return metadata;
327
328     }
329
330     public void setWagonFactory( WagonFactory wagonFactory )
331     {
332         this.wagonFactory = wagonFactory;
333     }
334
335     private List<org.apache.archiva.metadata.model.Dependency> convertDependencies( List<Dependency> dependencies )
336     {
337         List<org.apache.archiva.metadata.model.Dependency> l =
338             new ArrayList<org.apache.archiva.metadata.model.Dependency>();
339         for ( Dependency dependency : dependencies )
340         {
341             org.apache.archiva.metadata.model.Dependency newDependency =
342                 new org.apache.archiva.metadata.model.Dependency();
343             newDependency.setArtifactId( dependency.getArtifactId() );
344             newDependency.setClassifier( dependency.getClassifier() );
345             newDependency.setGroupId( dependency.getGroupId() );
346             newDependency.setOptional( dependency.isOptional() );
347             newDependency.setScope( dependency.getScope() );
348             newDependency.setSystemPath( dependency.getSystemPath() );
349             newDependency.setType( dependency.getType() );
350             newDependency.setVersion( dependency.getVersion() );
351             l.add( newDependency );
352         }
353         return l;
354     }
355
356     private org.apache.archiva.metadata.model.Scm convertScm( Scm scm )
357     {
358         org.apache.archiva.metadata.model.Scm newScm = null;
359         if ( scm != null )
360         {
361             newScm = new org.apache.archiva.metadata.model.Scm();
362             newScm.setConnection( scm.getConnection() );
363             newScm.setDeveloperConnection( scm.getDeveloperConnection() );
364             newScm.setUrl( scm.getUrl() );
365         }
366         return newScm;
367     }
368
369     private org.apache.archiva.metadata.model.Organization convertOrganization( Organization organization )
370     {
371         org.apache.archiva.metadata.model.Organization org = null;
372         if ( organization != null )
373         {
374             org = new org.apache.archiva.metadata.model.Organization();
375             org.setName( organization.getName() );
376             org.setUrl( organization.getUrl() );
377         }
378         return org;
379     }
380
381     private List<org.apache.archiva.metadata.model.License> convertLicenses( List<License> licenses )
382     {
383         List<org.apache.archiva.metadata.model.License> l = new ArrayList<org.apache.archiva.metadata.model.License>();
384         for ( License license : licenses )
385         {
386             org.apache.archiva.metadata.model.License newLicense = new org.apache.archiva.metadata.model.License();
387             newLicense.setName( license.getName() );
388             newLicense.setUrl( license.getUrl() );
389             l.add( newLicense );
390         }
391         return l;
392     }
393
394     private List<org.apache.archiva.metadata.model.MailingList> convertMailingLists( List<MailingList> mailingLists )
395     {
396         List<org.apache.archiva.metadata.model.MailingList> l =
397             new ArrayList<org.apache.archiva.metadata.model.MailingList>();
398         for ( MailingList mailingList : mailingLists )
399         {
400             org.apache.archiva.metadata.model.MailingList newMailingList =
401                 new org.apache.archiva.metadata.model.MailingList();
402             newMailingList.setName( mailingList.getName() );
403             newMailingList.setMainArchiveUrl( mailingList.getArchive() );
404             newMailingList.setPostAddress( mailingList.getPost() );
405             newMailingList.setSubscribeAddress( mailingList.getSubscribe() );
406             newMailingList.setUnsubscribeAddress( mailingList.getUnsubscribe() );
407             newMailingList.setOtherArchives( mailingList.getOtherArchives() );
408             l.add( newMailingList );
409         }
410         return l;
411     }
412
413     private org.apache.archiva.metadata.model.IssueManagement convertIssueManagement( IssueManagement issueManagement )
414     {
415         org.apache.archiva.metadata.model.IssueManagement im = null;
416         if ( issueManagement != null )
417         {
418             im = new org.apache.archiva.metadata.model.IssueManagement();
419             im.setSystem( issueManagement.getSystem() );
420             im.setUrl( issueManagement.getUrl() );
421         }
422         return im;
423     }
424
425     private org.apache.archiva.metadata.model.CiManagement convertCiManagement( CiManagement ciManagement )
426     {
427         org.apache.archiva.metadata.model.CiManagement ci = null;
428         if ( ciManagement != null )
429         {
430             ci = new org.apache.archiva.metadata.model.CiManagement();
431             ci.setSystem( ciManagement.getSystem() );
432             ci.setUrl( ciManagement.getUrl() );
433         }
434         return ci;
435     }
436
437     public Collection<String> listRootNamespaces( String repoId, Filter<String> filter )
438         throws RepositoryAdminException
439     {
440         File dir = getRepositoryBasedir( repoId );
441
442         return getSortedFiles( dir, filter );
443     }
444
445     private static Collection<String> getSortedFiles( File dir, Filter<String> filter )
446     {
447         List<String> fileNames;
448         String[] files = dir.list( new DirectoryFilter( filter ) );
449         if ( files != null )
450         {
451             fileNames = new ArrayList<String>( Arrays.asList( files ) );
452             Collections.sort( fileNames );
453         }
454         else
455         {
456             fileNames = Collections.emptyList();
457         }
458         return fileNames;
459     }
460
461     private File getRepositoryBasedir( String repoId )
462         throws RepositoryAdminException
463     {
464         ManagedRepository repositoryConfiguration = managedRepositoryAdmin.getManagedRepository( repoId );
465
466         return new File( repositoryConfiguration.getLocation() );
467     }
468
469     public Collection<String> listNamespaces( String repoId, String namespace, Filter<String> filter )
470         throws RepositoryAdminException
471     {
472         File dir = pathTranslator.toFile( getRepositoryBasedir( repoId ), namespace );
473
474         // scan all the directories which are potential namespaces. Any directories known to be projects are excluded
475         List<String> namespaces = new ArrayList<String>();
476         File[] files = dir.listFiles( new DirectoryFilter( filter ) );
477         if ( files != null )
478         {
479             for ( File file : files )
480             {
481                 if ( !isProject( file, filter ) )
482                 {
483                     namespaces.add( file.getName() );
484                 }
485             }
486         }
487         Collections.sort( namespaces );
488         return namespaces;
489     }
490
491     public Collection<String> listProjects( String repoId, String namespace, Filter<String> filter )
492         throws RepositoryAdminException
493     {
494         File dir = pathTranslator.toFile( getRepositoryBasedir( repoId ), namespace );
495
496         // scan all directories in the namespace, and only include those that are known to be projects
497         List<String> projects = new ArrayList<String>();
498         File[] files = dir.listFiles( new DirectoryFilter( filter ) );
499         if ( files != null )
500         {
501             for ( File file : files )
502             {
503                 if ( isProject( file, filter ) )
504                 {
505                     projects.add( file.getName() );
506                 }
507             }
508         }
509         Collections.sort( projects );
510         return projects;
511     }
512
513     public Collection<String> listProjectVersions( String repoId, String namespace, String projectId,
514                                                    Filter<String> filter )
515         throws RepositoryAdminException
516     {
517         File dir = pathTranslator.toFile( getRepositoryBasedir( repoId ), namespace, projectId );
518
519         // all directories in a project directory can be considered a version
520         return getSortedFiles( dir, filter );
521     }
522
523     public Collection<ArtifactMetadata> readArtifactsMetadata( String repoId, String namespace, String projectId,
524                                                                String projectVersion, Filter<String> filter )
525         throws RepositoryAdminException
526     {
527         File dir = pathTranslator.toFile( getRepositoryBasedir( repoId ), namespace, projectId, projectVersion );
528
529         // all files that are not metadata and not a checksum / signature are considered artifacts
530         File[] files = dir.listFiles( new ArtifactDirectoryFilter( filter ) );
531
532         List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>();
533         if ( files != null )
534         {
535             for ( File file : files )
536             {
537                 ArtifactMetadata metadata = getArtifactFromFile( repoId, namespace, projectId, projectVersion, file );
538                 artifacts.add( metadata );
539             }
540         }
541         return artifacts;
542     }
543
544     public ArtifactMetadata readArtifactMetadataFromPath( String repoId, String path )
545         throws RepositoryAdminException
546     {
547         ArtifactMetadata metadata = pathTranslator.getArtifactForPath( repoId, path );
548
549         populateArtifactMetadataFromFile( metadata, new File( getRepositoryBasedir( repoId ), path ) );
550
551         return metadata;
552     }
553
554     private ArtifactMetadata getArtifactFromFile( String repoId, String namespace, String projectId,
555                                                   String projectVersion, File file )
556     {
557         ArtifactMetadata metadata =
558             pathTranslator.getArtifactFromId( repoId, namespace, projectId, projectVersion, file.getName() );
559
560         populateArtifactMetadataFromFile( metadata, file );
561
562         return metadata;
563     }
564
565     private static void populateArtifactMetadataFromFile( ArtifactMetadata metadata, File file )
566     {
567         metadata.setWhenGathered( new Date() );
568         metadata.setFileLastModified( file.lastModified() );
569         ChecksummedFile checksummedFile = new ChecksummedFile( file );
570         try
571         {
572             metadata.setMd5( checksummedFile.calculateChecksum( ChecksumAlgorithm.MD5 ) );
573         }
574         catch ( IOException e )
575         {
576             log.error( "Unable to checksum file " + file + ": " + e.getMessage() );
577         }
578         try
579         {
580             metadata.setSha1( checksummedFile.calculateChecksum( ChecksumAlgorithm.SHA1 ) );
581         }
582         catch ( IOException e )
583         {
584             log.error( "Unable to checksum file " + file + ": " + e.getMessage() );
585         }
586         metadata.setSize( file.length() );
587     }
588
589     private boolean isProject( File dir, Filter<String> filter )
590     {
591         // scan directories for a valid project version subdirectory, meaning this must be a project directory
592         File[] files = dir.listFiles( new DirectoryFilter( filter ) );
593         if ( files != null )
594         {
595             for ( File file : files )
596             {
597                 if ( isProjectVersion( file ) )
598                 {
599                     return true;
600                 }
601             }
602         }
603
604         // if a metadata file is present, check if this is the "artifactId" directory, marking it as a project
605         MavenRepositoryMetadata metadata = readMetadata( dir );
606         if ( metadata != null && dir.getName().equals( metadata.getArtifactId() ) )
607         {
608             return true;
609         }
610
611         return false;
612     }
613
614     private boolean isProjectVersion( File dir )
615     {
616         final String artifactId = dir.getParentFile().getName();
617         final String projectVersion = dir.getName();
618
619         // check if there is a POM artifact file to ensure it is a version directory
620         File[] files;
621         if ( VersionUtil.isSnapshot( projectVersion ) )
622         {
623             files = dir.listFiles( new FilenameFilter()
624             {
625                 public boolean accept( File dir, String name )
626                 {
627                     if ( name.startsWith( artifactId + "-" ) && name.endsWith( ".pom" ) )
628                     {
629                         String v = name.substring( artifactId.length() + 1, name.length() - 4 );
630                         v = VersionUtil.getBaseVersion( v );
631                         if ( v.equals( projectVersion ) )
632                         {
633                             return true;
634                         }
635                     }
636                     return false;
637                 }
638             } );
639         }
640         else
641         {
642             final String pomFile = artifactId + "-" + projectVersion + ".pom";
643             files = dir.listFiles( new FilenameFilter()
644             {
645                 public boolean accept( File dir, String name )
646                 {
647                     return pomFile.equals( name );
648                 }
649             } );
650         }
651         if ( files != null && files.length > 0 )
652         {
653             return true;
654         }
655
656         // if a metadata file is present, check if this is the "version" directory, marking it as a project version
657         MavenRepositoryMetadata metadata = readMetadata( dir );
658         if ( metadata != null && projectVersion.equals( metadata.getVersion() ) )
659         {
660             return true;
661         }
662
663         return false;
664     }
665
666     private MavenRepositoryMetadata readMetadata( File directory )
667     {
668         MavenRepositoryMetadata metadata = null;
669         File metadataFile = new File( directory, METADATA_FILENAME );
670         if ( metadataFile.exists() )
671         {
672             try
673             {
674                 metadata = MavenRepositoryMetadataReader.read( metadataFile );
675             }
676             catch ( XMLException e )
677             {
678                 // ignore missing or invalid metadata
679             }
680         }
681         return metadata;
682     }
683
684     private static class DirectoryFilter
685         implements FilenameFilter
686     {
687         private final Filter<String> filter;
688
689         public DirectoryFilter( Filter<String> filter )
690         {
691             this.filter = filter;
692         }
693
694         public boolean accept( File dir, String name )
695         {
696             if ( !filter.accept( name ) )
697             {
698                 return false;
699             }
700             else if ( name.startsWith( "." ) )
701             {
702                 return false;
703             }
704             else if ( !new File( dir, name ).isDirectory() )
705             {
706                 return false;
707             }
708             return true;
709         }
710     }
711
712     private class ArtifactDirectoryFilter
713         implements FilenameFilter
714     {
715         private final Filter<String> filter;
716
717         public ArtifactDirectoryFilter( Filter<String> filter )
718         {
719             this.filter = filter;
720         }
721
722         public boolean accept( File dir, String name )
723         {
724             // TODO compare to logic in maven-repository-layer
725             if ( !filter.accept( name ) )
726             {
727                 return false;
728             }
729             else if ( name.startsWith( "." ) )
730             {
731                 return false;
732             }
733             else if ( name.endsWith( ".md5" ) || name.endsWith( ".sha1" ) || name.endsWith( ".asc" ) )
734             {
735                 return false;
736             }
737             else if ( name.equals( METADATA_FILENAME ) )
738             {
739                 return false;
740             }
741             else if ( new File( dir, name ).isDirectory() )
742             {
743                 return false;
744             }
745             return true;
746         }
747     }
748 }