]> source.dussan.org Git - archiva.git/blob
f4f6ce588c15017c5b061e318742fdee44a53693
[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.checksum.ChecksumAlgorithm;
23 import org.apache.archiva.checksum.ChecksummedFile;
24 import org.apache.archiva.metadata.model.ArtifactMetadata;
25 import org.apache.archiva.metadata.model.ProjectMetadata;
26 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
27 import org.apache.archiva.metadata.model.ProjectVersionReference;
28 import org.apache.archiva.metadata.repository.MetadataRepository;
29 import org.apache.archiva.metadata.repository.MetadataResolutionException;
30 import org.apache.archiva.metadata.repository.filter.AllFilter;
31 import org.apache.archiva.metadata.repository.filter.Filter;
32 import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
33 import org.apache.archiva.metadata.repository.storage.StorageMetadataResolver;
34 import org.apache.archiva.reports.RepositoryProblemFacet;
35 import org.apache.maven.archiva.common.utils.VersionUtil;
36 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
37 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
38 import org.apache.maven.archiva.xml.XMLException;
39 import org.apache.maven.model.CiManagement;
40 import org.apache.maven.model.Dependency;
41 import org.apache.maven.model.IssueManagement;
42 import org.apache.maven.model.License;
43 import org.apache.maven.model.MailingList;
44 import org.apache.maven.model.Model;
45 import org.apache.maven.model.Organization;
46 import org.apache.maven.model.Scm;
47 import org.apache.maven.model.building.DefaultModelBuildingRequest;
48 import org.apache.maven.model.building.ModelBuilder;
49 import org.apache.maven.model.building.ModelBuildingException;
50 import org.apache.maven.model.building.ModelBuildingRequest;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 import java.io.File;
55 import java.io.FilenameFilter;
56 import java.io.IOException;
57 import java.util.ArrayList;
58 import java.util.Arrays;
59 import java.util.Collection;
60 import java.util.Collections;
61 import java.util.Date;
62 import java.util.List;
63 import java.util.regex.Matcher;
64 import java.util.regex.Pattern;
65
66 /**
67  * @plexus.component role="org.apache.archiva.metadata.repository.storage.StorageMetadataResolver" role-hint="maven2"
68  */
69 public class Maven2RepositoryMetadataResolver
70     implements StorageMetadataResolver
71 {
72     /**
73      * @plexus.requirement
74      */
75     private ModelBuilder builder;
76
77     /**
78      * @plexus.requirement
79      */
80     private ArchivaConfiguration archivaConfiguration;
81
82     /**
83      * @plexus.requirement role-hint="maven2"
84      */
85     private RepositoryPathTranslator pathTranslator;
86
87     /**
88      * @plexus.requirement
89      */
90     private MetadataRepository metadataRepository;
91
92     private final static Logger log = LoggerFactory.getLogger( Maven2RepositoryMetadataResolver.class );
93
94     private static final String METADATA_FILENAME = "maven-metadata.xml";
95
96     private static final Filter<String> ALL = new AllFilter<String>();
97
98     private static final String PROBLEM_MISSING_POM = "missing-pom";
99
100     private static final String PROBLEM_INVALID_POM = "invalid-pom";
101
102     private static final String PROBLEM_MISLOCATED_POM = "mislocated-pom";
103
104     private static final List<String> POTENTIAL_PROBLEMS = Arrays.asList( PROBLEM_INVALID_POM, PROBLEM_MISSING_POM,
105                                                                           PROBLEM_MISLOCATED_POM );
106
107     public ProjectMetadata getProject( String repoId, String namespace, String projectId )
108     {
109         // TODO: could natively implement the "shared model" concept from the browse action to avoid needing it there?
110         return null;
111     }
112
113     public ProjectVersionMetadata getProjectVersion( String repoId, String namespace, String projectId,
114                                                      String projectVersion )
115         throws MetadataResolutionException
116     {
117         // TODO: an event mechanism would remove coupling to the problem reporting plugin
118         // TODO: this removes all problems - do we need something that just removes the problems created by this resolver?
119         String name = RepositoryProblemFacet.createName( namespace, projectId, projectVersion, null );
120         metadataRepository.removeMetadataFacet( repoId, RepositoryProblemFacet.FACET_ID, name );
121
122         ManagedRepositoryConfiguration repositoryConfiguration =
123             archivaConfiguration.getConfiguration().findManagedRepositoryById( repoId );
124
125         String artifactVersion = projectVersion;
126
127         File basedir = new File( repositoryConfiguration.getLocation() );
128         if ( VersionUtil.isSnapshot( projectVersion ) )
129         {
130             File metadataFile = pathTranslator.toFile( basedir, namespace, projectId, projectVersion,
131                                                        METADATA_FILENAME );
132             try
133             {
134                 MavenRepositoryMetadata metadata = MavenRepositoryMetadataReader.read( metadataFile );
135
136                 // re-adjust to timestamp if present, otherwise retain the original -SNAPSHOT filename
137                 MavenRepositoryMetadata.Snapshot snapshotVersion = metadata.getSnapshotVersion();
138                 if ( snapshotVersion != null )
139                 {
140                     artifactVersion = artifactVersion.substring( 0, artifactVersion.length() -
141                         8 ); // remove SNAPSHOT from end
142                     artifactVersion =
143                         artifactVersion + snapshotVersion.getTimestamp() + "-" + snapshotVersion.getBuildNumber();
144                 }
145             }
146             catch ( XMLException e )
147             {
148                 // unable to parse metadata - log it, and continue with the version as the original SNAPSHOT version
149                 log.warn( "Invalid metadata: " + metadataFile + " - " + e.getMessage() );
150             }
151         }
152
153         String id = projectId + "-" + artifactVersion + ".pom";
154         File file = pathTranslator.toFile( basedir, namespace, projectId, projectVersion, id );
155
156         if ( !file.exists() )
157         {
158             // TODO: an event mechanism would remove coupling to the problem reporting plugin
159             addProblemReport( repoId, namespace, projectId, projectVersion, PROBLEM_MISSING_POM,
160                               "The artifact's POM file '" + file + "' was missing" );
161
162             // metadata could not be resolved
163             return null;
164         }
165
166         ModelBuildingRequest req = new DefaultModelBuildingRequest();
167         req.setProcessPlugins( false );
168         req.setPomFile( file );
169         req.setModelResolver( new RepositoryModelResolver( basedir, pathTranslator ) );
170         req.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
171
172         Model model;
173         try
174         {
175             model = builder.build( req ).getEffectiveModel();
176         }
177         catch ( ModelBuildingException e )
178         {
179             addProblemReport( repoId, namespace, projectId, projectVersion, PROBLEM_INVALID_POM,
180                               "The artifact's POM file '" + file + "' was invalid: " + e.getMessage() );
181
182             throw new MetadataResolutionException( e.getMessage() );
183         }
184
185         // Check if the POM is in the correct location
186         boolean correctGroupId = namespace.equals( model.getGroupId() );
187         boolean correctArtifactId = projectId.equals( model.getArtifactId() );
188         boolean correctVersion = projectVersion.equals( model.getVersion() );
189         if ( !correctGroupId || !correctArtifactId || !correctVersion )
190         {
191             StringBuilder message = new StringBuilder( "Incorrect POM coordinates in '" + file + "':" );
192             if ( !correctGroupId )
193             {
194                 message.append( "\nIncorrect group ID: " ).append( model.getGroupId() );
195             }
196             if ( !correctArtifactId )
197             {
198                 message.append( "\nIncorrect artifact ID: " ).append( model.getArtifactId() );
199             }
200             if ( !correctVersion )
201             {
202                 message.append( "\nIncorrect version: " ).append( model.getVersion() );
203             }
204
205             String msg = message.toString();
206             addProblemReport( repoId, namespace, projectId, projectVersion, PROBLEM_MISLOCATED_POM, msg );
207
208             throw new MetadataResolutionException( msg );
209         }
210
211         ProjectVersionMetadata metadata = new ProjectVersionMetadata();
212         metadata.setCiManagement( convertCiManagement( model.getCiManagement() ) );
213         metadata.setDescription( model.getDescription() );
214         metadata.setId( projectVersion );
215         metadata.setIssueManagement( convertIssueManagement( model.getIssueManagement() ) );
216         metadata.setLicenses( convertLicenses( model.getLicenses() ) );
217         metadata.setMailingLists( convertMailingLists( model.getMailingLists() ) );
218         metadata.setDependencies( convertDependencies( model.getDependencies() ) );
219         metadata.setName( model.getName() );
220         metadata.setOrganization( convertOrganization( model.getOrganization() ) );
221         metadata.setScm( convertScm( model.getScm() ) );
222         metadata.setUrl( model.getUrl() );
223
224         MavenProjectFacet facet = new MavenProjectFacet();
225         facet.setGroupId( model.getGroupId() != null ? model.getGroupId() : model.getParent().getGroupId() );
226         facet.setArtifactId( model.getArtifactId() );
227         facet.setPackaging( model.getPackaging() );
228         if ( model.getParent() != null )
229         {
230             MavenProjectParent parent = new MavenProjectParent();
231             parent.setGroupId( model.getParent().getGroupId() );
232             parent.setArtifactId( model.getParent().getArtifactId() );
233             parent.setVersion( model.getParent().getVersion() );
234             facet.setParent( parent );
235         }
236         metadata.addFacet( facet );
237
238         return metadata;
239     }
240
241     private void addProblemReport( String repoId, String namespace, String projectId, String projectVersion,
242                                    String problemId, String message )
243     {
244         // TODO: an event mechanism would remove coupling to the problem reporting plugin
245         RepositoryProblemFacet problem = new RepositoryProblemFacet();
246         problem.setProblem( problemId );
247         problem.setMessage( message );
248         problem.setProject( projectId );
249         problem.setNamespace( namespace );
250         problem.setRepositoryId( repoId );
251         problem.setVersion( projectVersion );
252
253         metadataRepository.addMetadataFacet( repoId, problem );
254     }
255
256     private List<org.apache.archiva.metadata.model.Dependency> convertDependencies( List<Dependency> dependencies )
257     {
258         List<org.apache.archiva.metadata.model.Dependency> l =
259             new ArrayList<org.apache.archiva.metadata.model.Dependency>();
260         for ( Dependency dependency : dependencies )
261         {
262             org.apache.archiva.metadata.model.Dependency newDependency =
263                 new org.apache.archiva.metadata.model.Dependency();
264             newDependency.setArtifactId( dependency.getArtifactId() );
265             newDependency.setClassifier( dependency.getClassifier() );
266             newDependency.setGroupId( dependency.getGroupId() );
267             newDependency.setOptional( dependency.isOptional() );
268             newDependency.setScope( dependency.getScope() );
269             newDependency.setSystemPath( dependency.getSystemPath() );
270             newDependency.setType( dependency.getType() );
271             newDependency.setVersion( dependency.getVersion() );
272             l.add( newDependency );
273         }
274         return l;
275     }
276
277     private org.apache.archiva.metadata.model.Scm convertScm( Scm scm )
278     {
279         org.apache.archiva.metadata.model.Scm newScm = null;
280         if ( scm != null )
281         {
282             newScm = new org.apache.archiva.metadata.model.Scm();
283             newScm.setConnection( scm.getConnection() );
284             newScm.setDeveloperConnection( scm.getDeveloperConnection() );
285             newScm.setUrl( scm.getUrl() );
286         }
287         return newScm;
288     }
289
290     private org.apache.archiva.metadata.model.Organization convertOrganization( Organization organization )
291     {
292         org.apache.archiva.metadata.model.Organization org = null;
293         if ( organization != null )
294         {
295             org = new org.apache.archiva.metadata.model.Organization();
296             org.setName( organization.getName() );
297             org.setUrl( organization.getUrl() );
298         }
299         return org;
300     }
301
302     private List<org.apache.archiva.metadata.model.License> convertLicenses( List<License> licenses )
303     {
304         List<org.apache.archiva.metadata.model.License> l = new ArrayList<org.apache.archiva.metadata.model.License>();
305         for ( License license : licenses )
306         {
307             org.apache.archiva.metadata.model.License newLicense = new org.apache.archiva.metadata.model.License();
308             newLicense.setName( license.getName() );
309             newLicense.setUrl( license.getUrl() );
310             l.add( newLicense );
311         }
312         return l;
313     }
314
315     private List<org.apache.archiva.metadata.model.MailingList> convertMailingLists( List<MailingList> mailingLists )
316     {
317         List<org.apache.archiva.metadata.model.MailingList> l =
318             new ArrayList<org.apache.archiva.metadata.model.MailingList>();
319         for ( MailingList mailingList : mailingLists )
320         {
321             org.apache.archiva.metadata.model.MailingList newMailingList =
322                 new org.apache.archiva.metadata.model.MailingList();
323             newMailingList.setName( mailingList.getName() );
324             newMailingList.setMainArchiveUrl( mailingList.getArchive() );
325             newMailingList.setPostAddress( mailingList.getPost() );
326             newMailingList.setSubscribeAddress( mailingList.getSubscribe() );
327             newMailingList.setUnsubscribeAddress( mailingList.getUnsubscribe() );
328             newMailingList.setOtherArchives( mailingList.getOtherArchives() );
329             l.add( newMailingList );
330         }
331         return l;
332     }
333
334     private org.apache.archiva.metadata.model.IssueManagement convertIssueManagement( IssueManagement issueManagement )
335     {
336         org.apache.archiva.metadata.model.IssueManagement im = null;
337         if ( issueManagement != null )
338         {
339             im = new org.apache.archiva.metadata.model.IssueManagement();
340             im.setSystem( issueManagement.getSystem() );
341             im.setUrl( issueManagement.getUrl() );
342         }
343         return im;
344     }
345
346     private org.apache.archiva.metadata.model.CiManagement convertCiManagement( CiManagement ciManagement )
347     {
348         org.apache.archiva.metadata.model.CiManagement ci = null;
349         if ( ciManagement != null )
350         {
351             ci = new org.apache.archiva.metadata.model.CiManagement();
352             ci.setSystem( ciManagement.getSystem() );
353             ci.setUrl( ciManagement.getUrl() );
354         }
355         return ci;
356     }
357
358     public Collection<String> getArtifactVersions( String repoId, String namespace, String projectId,
359                                                    String projectVersion )
360     {
361         // TODO: useful, but not implemented yet, not called from DefaultMetadataResolver
362         throw new UnsupportedOperationException();
363     }
364
365     public Collection<ProjectVersionReference> getProjectReferences( String repoId, String namespace, String projectId,
366                                                                      String projectVersion )
367     {
368         // Can't be determined on a Maven 2 repository
369         throw new UnsupportedOperationException();
370     }
371
372     public Collection<String> getRootNamespaces( String repoId )
373     {
374         return getRootNamespaces( repoId, ALL );
375     }
376
377     public Collection<String> getRootNamespaces( String repoId, Filter<String> filter )
378     {
379         File dir = getRepositoryBasedir( repoId );
380
381         List<String> rootNamespaces;
382         String[] files = dir.list( new DirectoryFilter( filter ) );
383         if ( files != null )
384         {
385             rootNamespaces = new ArrayList<String>( Arrays.asList( files ) );
386             Collections.sort( rootNamespaces );
387         }
388         else
389         {
390             rootNamespaces = Collections.emptyList();
391         }
392         return rootNamespaces;
393     }
394
395     private File getRepositoryBasedir( String repoId )
396     {
397         ManagedRepositoryConfiguration repositoryConfiguration =
398             archivaConfiguration.getConfiguration().findManagedRepositoryById( repoId );
399
400         return new File( repositoryConfiguration.getLocation() );
401     }
402
403     public Collection<String> getNamespaces( String repoId, String namespace )
404     {
405         return getNamespaces( repoId, namespace, ALL );
406     }
407
408     public Collection<String> getNamespaces( String repoId, String namespace, Filter<String> filter )
409     {
410         File dir = pathTranslator.toFile( getRepositoryBasedir( repoId ), namespace );
411
412         // scan all the directories which are potential namespaces. Any directories known to be projects are excluded
413         List<String> namespaces = new ArrayList<String>();
414         File[] files = dir.listFiles( new DirectoryFilter( filter ) );
415         if ( files != null )
416         {
417             for ( File file : files )
418             {
419                 if ( !isProject( file, filter ) )
420                 {
421                     namespaces.add( file.getName() );
422                 }
423             }
424         }
425         Collections.sort( namespaces );
426         return namespaces;
427     }
428
429     public Collection<String> getProjects( String repoId, String namespace )
430     {
431         return getProjects( repoId, namespace, ALL );
432     }
433
434     public Collection<String> getProjects( String repoId, String namespace, Filter<String> filter )
435     {
436         File dir = pathTranslator.toFile( getRepositoryBasedir( repoId ), namespace );
437
438         // scan all directories in the namespace, and only include those that are known to be projects
439         List<String> projects = new ArrayList<String>();
440         File[] files = dir.listFiles( new DirectoryFilter( filter ) );
441         if ( files != null )
442         {
443             for ( File file : files )
444             {
445                 if ( isProject( file, filter ) )
446                 {
447                     projects.add( file.getName() );
448                 }
449             }
450         }
451         Collections.sort( projects );
452         return projects;
453     }
454
455     public Collection<String> getProjectVersions( String repoId, String namespace, String projectId )
456     {
457         return getProjectVersions( repoId, namespace, projectId, ALL );
458     }
459
460     public Collection<ArtifactMetadata> getArtifacts( String repoId, String namespace, String projectId,
461                                                       String projectVersion )
462     {
463         return getArtifacts( repoId, namespace, projectId, projectVersion, ALL );
464     }
465
466     public Collection<String> getProjectVersions( String repoId, String namespace, String projectId,
467                                                   Filter<String> filter )
468     {
469         File dir = pathTranslator.toFile( getRepositoryBasedir( repoId ), namespace, projectId );
470
471         // all directories in a project directory can be considered a version
472         String[] files = dir.list( new DirectoryFilter( filter ) );
473         return files != null ? Arrays.asList( files ) : Collections.<String>emptyList();
474     }
475
476     public Collection<ArtifactMetadata> getArtifacts( String repoId, String namespace, String projectId,
477                                                       String projectVersion, Filter<String> filter )
478     {
479         File dir = pathTranslator.toFile( getRepositoryBasedir( repoId ), namespace, projectId, projectVersion );
480
481         // all files that are not metadata and not a checksum / signature are considered artifacts
482         File[] files = dir.listFiles( new ArtifactDirectoryFilter( filter ) );
483
484         List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>();
485         if ( files != null )
486         {
487             for ( File file : files )
488             {
489                 ArtifactMetadata metadata = new ArtifactMetadata();
490                 metadata.setId( file.getName() );
491                 metadata.setProject( projectId );
492                 metadata.setNamespace( namespace );
493                 metadata.setRepositoryId( repoId );
494                 metadata.setWhenGathered( new Date() );
495                 metadata.setFileLastModified( file.lastModified() );
496                 ChecksummedFile checksummedFile = new ChecksummedFile( file );
497                 try
498                 {
499                     metadata.setMd5( checksummedFile.calculateChecksum( ChecksumAlgorithm.MD5 ) );
500                 }
501                 catch ( IOException e )
502                 {
503                     log.error( "Unable to checksum file " + file + ": " + e.getMessage() );
504                 }
505                 try
506                 {
507                     metadata.setSha1( checksummedFile.calculateChecksum( ChecksumAlgorithm.SHA1 ) );
508                 }
509                 catch ( IOException e )
510                 {
511                     log.error( "Unable to checksum file " + file + ": " + e.getMessage() );
512                 }
513                 metadata.setSize( file.length() );
514
515                 // TODO: very crude, migrate the functionality from the repository-layer here
516                 if ( VersionUtil.isGenericSnapshot( projectVersion ) )
517                 {
518                     String mainVersion = projectVersion.substring( 0, projectVersion.length() -
519                         8 ); // 8 is length of "SNAPSHOT"
520                     Matcher m = Pattern.compile(
521                         projectId + "-" + mainVersion + "([0-9]{8}.[0-9]{6}-[0-9]+).*" ).matcher( file.getName() );
522                     m.matches();
523                     String version = mainVersion + m.group( 1 );
524
525                     metadata.setVersion( version );
526                 }
527                 else
528                 {
529                     metadata.setVersion( projectVersion );
530                 }
531                 artifacts.add( metadata );
532             }
533         }
534         return artifacts;
535     }
536
537     private boolean isProject( File dir, Filter<String> filter )
538     {
539         // scan directories for a valid project version subdirectory, meaning this must be a project directory
540         File[] files = dir.listFiles( new DirectoryFilter( filter ) );
541         if ( files != null )
542         {
543             for ( File file : files )
544             {
545                 if ( isProjectVersion( file ) )
546                 {
547                     return true;
548                 }
549             }
550         }
551
552         // if a metadata file is present, check if this is the "artifactId" directory, marking it as a project
553         MavenRepositoryMetadata metadata = readMetadata( dir );
554         if ( metadata != null && dir.getName().equals( metadata.getArtifactId() ) )
555         {
556             return true;
557         }
558
559         return false;
560     }
561
562     private boolean isProjectVersion( File dir )
563     {
564         final String artifactId = dir.getParentFile().getName();
565         final String projectVersion = dir.getName();
566
567         // check if there is a POM artifact file to ensure it is a version directory
568         File[] files;
569         if ( VersionUtil.isSnapshot( projectVersion ) )
570         {
571             files = dir.listFiles( new FilenameFilter()
572             {
573                 public boolean accept( File dir, String name )
574                 {
575                     if ( name.startsWith( artifactId + "-" ) && name.endsWith( ".pom" ) )
576                     {
577                         String v = name.substring( artifactId.length() + 1, name.length() - 4 );
578                         v = VersionUtil.getBaseVersion( v );
579                         if ( v.equals( projectVersion ) )
580                         {
581                             return true;
582                         }
583                     }
584                     return false;
585                 }
586             } );
587         }
588         else
589         {
590             final String pomFile = artifactId + "-" + projectVersion + ".pom";
591             files = dir.listFiles( new FilenameFilter()
592             {
593                 public boolean accept( File dir, String name )
594                 {
595                     return pomFile.equals( name );
596                 }
597             } );
598         }
599         if ( files != null && files.length > 0 )
600         {
601             return true;
602         }
603
604         // if a metadata file is present, check if this is the "version" directory, marking it as a project version
605         MavenRepositoryMetadata metadata = readMetadata( dir );
606         if ( metadata != null && projectVersion.equals( metadata.getVersion() ) )
607         {
608             return true;
609         }
610
611         return false;
612     }
613
614     private MavenRepositoryMetadata readMetadata( File directory )
615     {
616         MavenRepositoryMetadata metadata = null;
617         File metadataFile = new File( directory, METADATA_FILENAME );
618         if ( metadataFile.exists() )
619         {
620             try
621             {
622                 metadata = MavenRepositoryMetadataReader.read( metadataFile );
623             }
624             catch ( XMLException e )
625             {
626                 // ignore missing or invalid metadata
627             }
628         }
629         return metadata;
630     }
631
632     public void setConfiguration( ArchivaConfiguration configuration )
633     {
634         this.archivaConfiguration = configuration;
635     }
636
637     private static class DirectoryFilter
638         implements FilenameFilter
639     {
640         private final Filter<String> filter;
641
642         public DirectoryFilter( Filter<String> filter )
643         {
644             this.filter = filter;
645         }
646
647         public boolean accept( File dir, String name )
648         {
649             if ( !filter.accept( name ) )
650             {
651                 return false;
652             }
653             else if ( name.startsWith( "." ) )
654             {
655                 return false;
656             }
657             else if ( !new File( dir, name ).isDirectory() )
658             {
659                 return false;
660             }
661             return true;
662         }
663     }
664
665     private class ArtifactDirectoryFilter
666         implements FilenameFilter
667     {
668         private final Filter<String> filter;
669
670         public ArtifactDirectoryFilter( Filter<String> filter )
671         {
672             this.filter = filter;
673         }
674
675         public boolean accept( File dir, String name )
676         {
677             // TODO compare to logic in maven-repository-layer
678             if ( !filter.accept( name ) )
679             {
680                 return false;
681             }
682             else if ( name.startsWith( "." ) )
683             {
684                 return false;
685             }
686             else if ( name.endsWith( ".md5" ) || name.endsWith( ".sha1" ) || name.endsWith( ".asc" ) )
687             {
688                 return false;
689             }
690             else if ( name.equals( METADATA_FILENAME ) )
691             {
692                 return false;
693             }
694             else if ( new File( dir, name ).isDirectory() )
695             {
696                 return false;
697             }
698             return true;
699         }
700     }
701 }