]> source.dussan.org Git - archiva.git/blob
da3c4447014a16e8d6f15bbc512bd74c8f8c4f66
[archiva.git] /
1 package org.apache.archiva.metadata.repository.file;
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.configuration.ArchivaConfiguration;
23 import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
24 import org.apache.archiva.metadata.model.ArtifactMetadata;
25 import org.apache.archiva.metadata.model.CiManagement;
26 import org.apache.archiva.metadata.model.Dependency;
27 import org.apache.archiva.metadata.model.IssueManagement;
28 import org.apache.archiva.metadata.model.License;
29 import org.apache.archiva.metadata.model.MailingList;
30 import org.apache.archiva.metadata.model.MetadataFacet;
31 import org.apache.archiva.metadata.model.MetadataFacetFactory;
32 import org.apache.archiva.metadata.model.Organization;
33 import org.apache.archiva.metadata.model.ProjectMetadata;
34 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
35 import org.apache.archiva.metadata.model.ProjectVersionReference;
36 import org.apache.archiva.metadata.model.Scm;
37 import org.apache.archiva.metadata.repository.MetadataRepository;
38 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
39 import org.apache.archiva.metadata.repository.MetadataResolutionException;
40 import org.apache.commons.io.FileUtils;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 import java.io.File;
45 import java.io.FileNotFoundException;
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.io.OutputStream;
49 import java.nio.file.Files;
50 import java.nio.file.NoSuchFileException;
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.Collection;
54 import java.util.Collections;
55 import java.util.Comparator;
56 import java.util.Date;
57 import java.util.HashMap;
58 import java.util.HashSet;
59 import java.util.LinkedHashSet;
60 import java.util.List;
61 import java.util.Map;
62 import java.util.Properties;
63 import java.util.Set;
64 import java.util.StringTokenizer;
65
66 public class FileMetadataRepository
67     implements MetadataRepository
68 {
69     private final Map<String, MetadataFacetFactory> metadataFacetFactories;
70
71     private final ArchivaConfiguration configuration;
72
73     private Logger log = LoggerFactory.getLogger( FileMetadataRepository.class );
74
75     private static final String PROJECT_METADATA_KEY = "project-metadata";
76
77     private static final String PROJECT_VERSION_METADATA_KEY = "version-metadata";
78
79     private static final String NAMESPACE_METADATA_KEY = "namespace-metadata";
80
81     private static final String METADATA_KEY = "metadata";
82
83     public FileMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories,
84                                    ArchivaConfiguration configuration )
85     {
86         this.metadataFacetFactories = metadataFacetFactories;
87         this.configuration = configuration;
88     }
89
90     private File getBaseDirectory( String repoId )
91         throws IOException
92     {
93         // TODO: should be configurable, like the index
94         ManagedRepositoryConfiguration managedRepositoryConfiguration =
95             configuration.getConfiguration().getManagedRepositoriesAsMap().get( repoId );
96         if ( managedRepositoryConfiguration == null )
97         {
98             return Files.createTempDirectory( repoId ).toFile();
99         }
100         String basedir = managedRepositoryConfiguration.getLocation();
101         return new File( basedir, ".archiva" );
102     }
103
104     private File getDirectory( String repoId )
105         throws IOException
106     {
107         return new File( getBaseDirectory( repoId ), "content" );
108     }
109
110     @Override
111     public void updateProject( String repoId, ProjectMetadata project )
112     {
113         updateProject( repoId, project.getNamespace(), project.getId() );
114     }
115
116     private void updateProject( String repoId, String namespace, String id )
117     {
118         // TODO: this is a more braindead implementation than we would normally expect, for prototyping purposes
119         updateNamespace( repoId, namespace );
120
121         try
122         {
123             File namespaceDirectory = new File( getDirectory( repoId ), namespace );
124             Properties properties = new Properties();
125             properties.setProperty( "namespace", namespace );
126             properties.setProperty( "id", id );
127             writeProperties( properties, new File( namespaceDirectory, id ), PROJECT_METADATA_KEY );
128         }
129         catch ( IOException e )
130         {
131             // TODO!
132             log.error( e.getMessage(), e );
133         }
134     }
135
136     @Override
137     public void updateProjectVersion( String repoId, String namespace, String projectId,
138                                       ProjectVersionMetadata versionMetadata )
139     {
140
141         try
142         {
143             updateProject( repoId, namespace, projectId );
144
145             File directory =
146                 new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + versionMetadata.getId() );
147
148             Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
149             // remove properties that are not references or artifacts
150             for ( Object key : new ArrayList( properties.keySet() ) )
151             {
152                 String name = (String) key;
153                 if ( !name.contains( ":" ) && !name.equals( "facetIds" ) )
154                 {
155                     properties.remove( name );
156                 }
157
158                 // clear the facet contents so old properties are no longer written
159                 clearMetadataFacetProperties( versionMetadata.getFacetList(), properties, "" );
160             }
161             properties.setProperty( "id", versionMetadata.getId() );
162             setProperty( properties, "name", versionMetadata.getName() );
163             setProperty( properties, "description", versionMetadata.getDescription() );
164             setProperty( properties, "url", versionMetadata.getUrl() );
165             setProperty( properties, "incomplete", String.valueOf( versionMetadata.isIncomplete() ) );
166             if ( versionMetadata.getScm() != null )
167             {
168                 setProperty( properties, "scm.connection", versionMetadata.getScm().getConnection() );
169                 setProperty( properties, "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection() );
170                 setProperty( properties, "scm.url", versionMetadata.getScm().getUrl() );
171             }
172             if ( versionMetadata.getCiManagement() != null )
173             {
174                 setProperty( properties, "ci.system", versionMetadata.getCiManagement().getSystem() );
175                 setProperty( properties, "ci.url", versionMetadata.getCiManagement().getUrl() );
176             }
177             if ( versionMetadata.getIssueManagement() != null )
178             {
179                 setProperty( properties, "issue.system", versionMetadata.getIssueManagement().getSystem() );
180                 setProperty( properties, "issue.url", versionMetadata.getIssueManagement().getUrl() );
181             }
182             if ( versionMetadata.getOrganization() != null )
183             {
184                 setProperty( properties, "org.name", versionMetadata.getOrganization().getName() );
185                 setProperty( properties, "org.url", versionMetadata.getOrganization().getUrl() );
186             }
187             int i = 0;
188             for ( License license : versionMetadata.getLicenses() )
189             {
190                 setProperty( properties, "license." + i + ".name", license.getName() );
191                 setProperty( properties, "license." + i + ".url", license.getUrl() );
192                 i++;
193             }
194             i = 0;
195             for ( MailingList mailingList : versionMetadata.getMailingLists() )
196             {
197                 setProperty( properties, "mailingList." + i + ".archive", mailingList.getMainArchiveUrl() );
198                 setProperty( properties, "mailingList." + i + ".name", mailingList.getName() );
199                 setProperty( properties, "mailingList." + i + ".post", mailingList.getPostAddress() );
200                 setProperty( properties, "mailingList." + i + ".unsubscribe", mailingList.getUnsubscribeAddress() );
201                 setProperty( properties, "mailingList." + i + ".subscribe", mailingList.getSubscribeAddress() );
202                 setProperty( properties, "mailingList." + i + ".otherArchives",
203                              join( mailingList.getOtherArchives() ) );
204                 i++;
205             }
206             i = 0;
207             ProjectVersionReference reference = new ProjectVersionReference();
208             reference.setNamespace( namespace );
209             reference.setProjectId( projectId );
210             reference.setProjectVersion( versionMetadata.getId() );
211             reference.setReferenceType( ProjectVersionReference.ReferenceType.DEPENDENCY );
212             for ( Dependency dependency : versionMetadata.getDependencies() )
213             {
214                 setProperty( properties, "dependency." + i + ".classifier", dependency.getClassifier() );
215                 setProperty( properties, "dependency." + i + ".scope", dependency.getScope() );
216                 setProperty( properties, "dependency." + i + ".systemPath", dependency.getSystemPath() );
217                 setProperty( properties, "dependency." + i + ".artifactId", dependency.getArtifactId() );
218                 setProperty( properties, "dependency." + i + ".groupId", dependency.getGroupId() );
219                 setProperty( properties, "dependency." + i + ".version", dependency.getVersion() );
220                 setProperty( properties, "dependency." + i + ".type", dependency.getType() );
221                 setProperty( properties, "dependency." + i + ".optional", String.valueOf( dependency.isOptional() ) );
222
223                 updateProjectReference( repoId, dependency.getGroupId(), dependency.getArtifactId(),
224                                         dependency.getVersion(), reference );
225
226                 i++;
227             }
228             Set<String> facetIds = new LinkedHashSet<String>( versionMetadata.getFacetIds() );
229             facetIds.addAll( Arrays.asList( properties.getProperty( "facetIds", "" ).split( "," ) ) );
230             properties.setProperty( "facetIds", join( facetIds ) );
231
232             updateProjectVersionFacets( versionMetadata, properties );
233
234             writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
235         }
236         catch ( IOException e )
237         {
238             // TODO
239             log.error( e.getMessage(), e );
240         }
241     }
242
243     private void updateProjectVersionFacets( ProjectVersionMetadata versionMetadata, Properties properties )
244     {
245         for ( MetadataFacet facet : versionMetadata.getFacetList() )
246         {
247             for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
248             {
249                 properties.setProperty( facet.getFacetId() + ":" + entry.getKey(), entry.getValue() );
250             }
251         }
252     }
253
254     private static void clearMetadataFacetProperties( Collection<MetadataFacet> facetList, Properties properties,
255                                                       String prefix )
256     {
257         List<Object> propsToRemove = new ArrayList<>();
258         for ( MetadataFacet facet : facetList )
259         {
260             for ( Object key : new ArrayList( properties.keySet() ) )
261             {
262                 String keyString = (String) key;
263                 if ( keyString.startsWith( prefix + facet.getFacetId() + ":" ) )
264                 {
265                     propsToRemove.add( key );
266                 }
267             }
268         }
269
270         for ( Object key : propsToRemove )
271         {
272             properties.remove( key );
273         }
274     }
275
276     private void updateProjectReference( String repoId, String namespace, String projectId, String projectVersion,
277                                          ProjectVersionReference reference )
278     {
279         try
280         {
281             File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
282
283             Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
284             int i = Integer.parseInt( properties.getProperty( "ref:lastReferenceNum", "-1" ) ) + 1;
285             setProperty( properties, "ref:lastReferenceNum", Integer.toString( i ) );
286             setProperty( properties, "ref:reference." + i + ".namespace", reference.getNamespace() );
287             setProperty( properties, "ref:reference." + i + ".projectId", reference.getProjectId() );
288             setProperty( properties, "ref:reference." + i + ".projectVersion", reference.getProjectVersion() );
289             setProperty( properties, "ref:reference." + i + ".referenceType", reference.getReferenceType().toString() );
290
291             writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
292         }
293         catch ( IOException e )
294         {
295             // TODO
296             log.error( e.getMessage(), e );
297         }
298     }
299
300     @Override
301     public void updateNamespace( String repoId, String namespace )
302     {
303         try
304         {
305             File namespaceDirectory = new File( getDirectory( repoId ), namespace );
306             Properties properties = new Properties();
307             properties.setProperty( "namespace", namespace );
308             writeProperties( properties, namespaceDirectory, NAMESPACE_METADATA_KEY );
309
310         }
311         catch ( IOException e )
312         {
313             // TODO!
314             log.error( e.getMessage(), e );
315         }
316     }
317
318     @Override
319     public List<String> getMetadataFacets( String repoId, String facetId )
320         throws MetadataRepositoryException
321     {
322         try
323         {
324             File directory = getMetadataDirectory( repoId, facetId );
325             List<String> facets = new ArrayList<>();
326             recurse( facets, "", directory );
327             return facets;
328         }
329         catch ( IOException e )
330         {
331             throw new MetadataRepositoryException( e.getMessage(), e );
332         }
333     }
334
335     @Override
336     public boolean hasMetadataFacet( String repositoryId, String facetId )
337         throws MetadataRepositoryException
338     {
339         // TODO could be improved a bit
340         return !getMetadataFacets( repositoryId, facetId ).isEmpty();
341     }
342
343     private void recurse( List<String> facets, String prefix, File directory )
344     {
345         File[] list = directory.listFiles();
346         if ( list != null )
347         {
348             for ( File dir : list )
349             {
350                 if ( dir.isDirectory() )
351                 {
352                     recurse( facets, prefix + "/" + dir.getName(), dir );
353                 }
354                 else if ( dir.getName().equals( METADATA_KEY + ".properties" ) )
355                 {
356                     facets.add( prefix.substring( 1 ) );
357                 }
358             }
359         }
360     }
361
362     @Override
363     public MetadataFacet getMetadataFacet( String repositoryId, String facetId, String name )
364     {
365         Properties properties;
366         try
367         {
368             properties =
369                 readProperties( new File( getMetadataDirectory( repositoryId, facetId ), name ), METADATA_KEY );
370         }
371         catch ( FileNotFoundException e )
372         {
373             return null;
374         }
375         catch ( IOException e )
376         {
377             // TODO
378             log.error( e.getMessage(), e );
379             return null;
380         }
381         MetadataFacet metadataFacet = null;
382         MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
383         if ( metadataFacetFactory != null )
384         {
385             metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
386             Map<String, String> map = new HashMap<>();
387             for ( Object key : new ArrayList( properties.keySet() ) )
388             {
389                 String property = (String) key;
390                 map.put( property, properties.getProperty( property ) );
391             }
392             metadataFacet.fromProperties( map );
393         }
394         return metadataFacet;
395     }
396
397     @Override
398     public void addMetadataFacet( String repositoryId, MetadataFacet metadataFacet )
399     {
400         Properties properties = new Properties();
401         properties.putAll( metadataFacet.toProperties() );
402
403         try
404         {
405             File directory =
406                 new File( getMetadataDirectory( repositoryId, metadataFacet.getFacetId() ), metadataFacet.getName() );
407             writeProperties( properties, directory, METADATA_KEY );
408         }
409         catch ( IOException e )
410         {
411             // TODO!
412             log.error( e.getMessage(), e );
413         }
414     }
415
416     @Override
417     public void removeMetadataFacets( String repositoryId, String facetId )
418         throws MetadataRepositoryException
419     {
420         try
421         {
422             File dir = getMetadataDirectory( repositoryId, facetId );
423             if ( !Files.deleteIfExists( dir.toPath() ) )
424             {
425                 log.error( "Cannot delete the metadata repository {}", dir );
426             }
427         }
428         catch ( IOException e )
429         {
430             throw new MetadataRepositoryException( e.getMessage(), e );
431         }
432     }
433
434     @Override
435     public void removeMetadataFacet( String repoId, String facetId, String name )
436         throws MetadataRepositoryException
437     {
438         try
439         {
440             File dir = new File( getMetadataDirectory( repoId, facetId ), name );
441             if ( !Files.deleteIfExists( dir.toPath() ) )
442             {
443                 log.error( "Cannot delete the metadata repository {}", dir );
444             }
445         }
446         catch ( IOException e )
447         {
448             throw new MetadataRepositoryException( e.getMessage(), e );
449         }
450     }
451
452     @Override
453     public List<ArtifactMetadata> getArtifactsByDateRange( String repoId, Date startTime, Date endTime )
454         throws MetadataRepositoryException
455     {
456         try
457         {
458             // TODO: this is quite slow - if we are to persist with this repository implementation we should build an index
459             //  of this information (eg. in Lucene, as before)
460
461             List<ArtifactMetadata> artifacts = new ArrayList<>();
462             for ( String ns : getRootNamespaces( repoId ) )
463             {
464                 getArtifactsByDateRange( artifacts, repoId, ns, startTime, endTime );
465             }
466             Collections.sort( artifacts, new ArtifactComparator() );
467             return artifacts;
468         }
469         catch ( MetadataResolutionException e )
470         {
471             throw new MetadataRepositoryException( e.getMessage(), e );
472         }
473     }
474
475     private void getArtifactsByDateRange( List<ArtifactMetadata> artifacts, String repoId, String ns, Date startTime,
476                                           Date endTime )
477         throws MetadataRepositoryException
478     {
479         try
480         {
481             for ( String namespace : getNamespaces( repoId, ns ) )
482             {
483                 getArtifactsByDateRange( artifacts, repoId, ns + "." + namespace, startTime, endTime );
484             }
485
486             for ( String project : getProjects( repoId, ns ) )
487             {
488                 for ( String version : getProjectVersions( repoId, ns, project ) )
489                 {
490                     for ( ArtifactMetadata artifact : getArtifacts( repoId, ns, project, version ) )
491                     {
492                         if ( startTime == null || startTime.before( artifact.getWhenGathered() ) )
493                         {
494                             if ( endTime == null || endTime.after( artifact.getWhenGathered() ) )
495                             {
496                                 artifacts.add( artifact );
497                             }
498                         }
499                     }
500                 }
501             }
502         }
503         catch ( MetadataResolutionException e )
504         {
505             throw new MetadataRepositoryException( e.getMessage(), e );
506         }
507     }
508
509     @Override
510     public Collection<ArtifactMetadata> getArtifacts( String repoId, String namespace, String projectId,
511                                                       String projectVersion )
512         throws MetadataResolutionException
513     {
514         try
515         {
516             Map<String, ArtifactMetadata> artifacts = new HashMap<>();
517
518             File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
519
520             Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
521
522             for ( Map.Entry entry : properties.entrySet() )
523             {
524                 String name = (String) entry.getKey();
525                 StringTokenizer tok = new StringTokenizer( name, ":" );
526                 if ( tok.hasMoreTokens() && "artifact".equals( tok.nextToken() ) )
527                 {
528                     String field = tok.nextToken();
529                     String id = tok.nextToken();
530
531                     ArtifactMetadata artifact = artifacts.get( id );
532                     if ( artifact == null )
533                     {
534                         artifact = new ArtifactMetadata();
535                         artifact.setRepositoryId( repoId );
536                         artifact.setNamespace( namespace );
537                         artifact.setProject( projectId );
538                         artifact.setProjectVersion( projectVersion );
539                         artifact.setVersion( projectVersion );
540                         artifact.setId( id );
541                         artifacts.put( id, artifact );
542                     }
543
544                     String value = (String) entry.getValue();
545                     if ( "updated".equals( field ) )
546                     {
547                         artifact.setFileLastModified( Long.parseLong( value ) );
548                     }
549                     else if ( "size".equals( field ) )
550                     {
551                         artifact.setSize( Long.valueOf( value ) );
552                     }
553                     else if ( "whenGathered".equals( field ) )
554                     {
555                         artifact.setWhenGathered( new Date( Long.parseLong( value ) ) );
556                     }
557                     else if ( "version".equals( field ) )
558                     {
559                         artifact.setVersion( value );
560                     }
561                     else if ( "md5".equals( field ) )
562                     {
563                         artifact.setMd5( value );
564                     }
565                     else if ( "sha1".equals( field ) )
566                     {
567                         artifact.setSha1( value );
568                     }
569                     else if ( "facetIds".equals( field ) )
570                     {
571                         if ( value.length() > 0 )
572                         {
573                             String propertyPrefix = "artifact:facet:" + id + ":";
574                             for ( String facetId : value.split( "," ) )
575                             {
576                                 MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
577                                 if ( factory == null )
578                                 {
579                                     log.error( "Attempted to load unknown artifact metadata facet: " + facetId );
580                                 }
581                                 else
582                                 {
583                                     MetadataFacet facet = factory.createMetadataFacet();
584                                     String prefix = propertyPrefix + facet.getFacetId();
585                                     Map<String, String> map = new HashMap<>();
586                                     for ( Object key : new ArrayList( properties.keySet() ) )
587                                     {
588                                         String property = (String) key;
589                                         if ( property.startsWith( prefix ) )
590                                         {
591                                             map.put( property.substring( prefix.length() + 1 ),
592                                                      properties.getProperty( property ) );
593                                         }
594                                     }
595                                     facet.fromProperties( map );
596                                     artifact.addFacet( facet );
597                                 }
598                             }
599                         }
600
601                         updateArtifactFacets( artifact, properties );
602                     }
603                 }
604             }
605             return artifacts.values();
606         }
607         catch ( IOException e )
608         {
609             throw new MetadataResolutionException( e.getMessage(), e );
610         }
611     }
612
613     @Override
614     public void save()
615     {
616         // it's all instantly persisted
617     }
618
619     @Override
620     public void close()
621     {
622         // nothing additional to close
623     }
624
625     @Override
626     public void revert()
627     {
628         log.warn( "Attempted to revert a session, but the file-based repository storage doesn't support it" );
629     }
630
631     @Override
632     public boolean canObtainAccess( Class<?> aClass )
633     {
634         return false;
635     }
636
637     @Override
638     public <T> T obtainAccess( Class<T> aClass )
639     {
640         throw new IllegalArgumentException(
641             "Access using " + aClass + " is not supported on the file metadata storage" );
642     }
643
644     private void updateArtifactFacets( ArtifactMetadata artifact, Properties properties )
645     {
646         String propertyPrefix = "artifact:facet:" + artifact.getId() + ":";
647         for ( MetadataFacet facet : artifact.getFacetList() )
648         {
649             for ( Map.Entry<String, String> e : facet.toProperties().entrySet() )
650             {
651                 String key = propertyPrefix + facet.getFacetId() + ":" + e.getKey();
652                 properties.setProperty( key, e.getValue() );
653             }
654         }
655     }
656
657     @Override
658     public Collection<String> getRepositories()
659     {
660         List<String> repositories = new ArrayList<>();
661         for ( ManagedRepositoryConfiguration managedRepositoryConfiguration : configuration.getConfiguration().getManagedRepositories() )
662         {
663             repositories.add( managedRepositoryConfiguration.getId() );
664         }
665         return repositories;
666     }
667
668     @Override
669     public List<ArtifactMetadata> getArtifactsByChecksum( String repositoryId, String checksum )
670         throws MetadataRepositoryException
671     {
672         try
673         {
674             // TODO: this is quite slow - if we are to persist with this repository implementation we should build an index
675             //  of this information (eg. in Lucene, as before)
676             // alternatively, we could build a referential tree in the content repository, however it would need some levels
677             // of depth to avoid being too broad to be useful (eg. /repository/checksums/a/ab/abcdef1234567)
678
679             List<ArtifactMetadata> artifacts = new ArrayList<>();
680             for ( String ns : getRootNamespaces( repositoryId ) )
681             {
682                 getArtifactsByChecksum( artifacts, repositoryId, ns, checksum );
683             }
684             return artifacts;
685         }
686         catch ( MetadataResolutionException e )
687         {
688             throw new MetadataRepositoryException( e.getMessage(), e );
689         }
690     }
691
692     @Override
693     public void removeNamespace( String repositoryId, String project )
694         throws MetadataRepositoryException
695     {
696         try
697         {
698             File namespaceDirectory = new File( getDirectory( repositoryId ), project );
699             FileUtils.deleteDirectory( namespaceDirectory );
700             //Properties properties = new Properties();
701             //properties.setProperty( "namespace", namespace );
702             //writeProperties( properties, namespaceDirectory, NAMESPACE_METADATA_KEY );
703
704         }
705         catch ( IOException e )
706         {
707             throw new MetadataRepositoryException( e.getMessage(), e );
708         }
709     }
710
711     @Override
712     public void removeArtifact( ArtifactMetadata artifactMetadata, String baseVersion )
713         throws MetadataRepositoryException
714     {
715
716         try
717         {
718             File directory = new File( getDirectory( artifactMetadata.getRepositoryId() ),
719                                        artifactMetadata.getNamespace() + "/" + artifactMetadata.getProject() + "/"
720                                            + baseVersion );
721
722             Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
723
724             String id = artifactMetadata.getId();
725
726             properties.remove( "artifact:updated:" + id );
727             properties.remove( "artifact:whenGathered:" + id );
728             properties.remove( "artifact:size:" + id );
729             properties.remove( "artifact:md5:" + id );
730             properties.remove( "artifact:sha1:" + id );
731             properties.remove( "artifact:version:" + id );
732             properties.remove( "artifact:facetIds:" + id );
733
734             String prefix = "artifact:facet:" + id + ":";
735             for ( Object key : new ArrayList( properties.keySet() ) )
736             {
737                 String property = (String) key;
738                 if ( property.startsWith( prefix ) )
739                 {
740                     properties.remove( property );
741                 }
742             }
743
744             writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
745         }
746         catch ( IOException e )
747         {
748             throw new MetadataRepositoryException( e.getMessage(), e );
749         }
750
751     }
752
753     @Override
754     public void removeArtifact( String repoId, String namespace, String project, String version, String id )
755         throws MetadataRepositoryException
756     {
757         try
758         {
759             File directory = new File( getDirectory( repoId ), namespace + "/" + project + "/" + version );
760
761             Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
762
763             properties.remove( "artifact:updated:" + id );
764             properties.remove( "artifact:whenGathered:" + id );
765             properties.remove( "artifact:size:" + id );
766             properties.remove( "artifact:md5:" + id );
767             properties.remove( "artifact:sha1:" + id );
768             properties.remove( "artifact:version:" + id );
769             properties.remove( "artifact:facetIds:" + id );
770
771             String prefix = "artifact:facet:" + id + ":";
772             for ( Object key : new ArrayList( properties.keySet() ) )
773             {
774                 String property = (String) key;
775                 if ( property.startsWith( prefix ) )
776                 {
777                     properties.remove( property );
778                 }
779             }
780
781             Files.deleteIfExists( directory.toPath() );
782             //writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
783         }
784         catch ( IOException e )
785         {
786             throw new MetadataRepositoryException( e.getMessage(), e );
787         }
788     }
789
790     /**
791      * FIXME implements this !!!!
792      *
793      * @param repositoryId
794      * @param namespace
795      * @param project
796      * @param projectVersion
797      * @param metadataFacet  will remove artifacts which have this {@link MetadataFacet} using equals
798      * @throws MetadataRepositoryException
799      */
800     @Override
801     public void removeArtifact( String repositoryId, String namespace, String project, String projectVersion,
802                                 MetadataFacet metadataFacet )
803         throws MetadataRepositoryException
804     {
805         throw new UnsupportedOperationException( "not implemented" );
806     }
807
808     @Override
809     public void removeRepository( String repoId )
810         throws MetadataRepositoryException
811     {
812         try
813         {
814             File dir = getDirectory( repoId );
815             if ( !Files.deleteIfExists( dir.toPath() ) )
816             {
817                 log.error( "Cannot delete repository {}", dir );
818             }
819         }
820         catch ( IOException e )
821         {
822             throw new MetadataRepositoryException( e.getMessage(), e );
823         }
824     }
825
826     private void getArtifactsByChecksum( List<ArtifactMetadata> artifacts, String repositoryId, String ns,
827                                          String checksum )
828         throws MetadataRepositoryException
829     {
830         try
831         {
832             for ( String namespace : getNamespaces( repositoryId, ns ) )
833             {
834                 getArtifactsByChecksum( artifacts, repositoryId, ns + "." + namespace, checksum );
835             }
836
837             for ( String project : getProjects( repositoryId, ns ) )
838             {
839                 for ( String version : getProjectVersions( repositoryId, ns, project ) )
840                 {
841                     for ( ArtifactMetadata artifact : getArtifacts( repositoryId, ns, project, version ) )
842                     {
843                         if ( checksum.equals( artifact.getMd5() ) || checksum.equals( artifact.getSha1() ) )
844                         {
845                             artifacts.add( artifact );
846                         }
847                     }
848                 }
849             }
850         }
851         catch ( MetadataResolutionException e )
852         {
853             throw new MetadataRepositoryException( e.getMessage(), e );
854         }
855     }
856
857     @Override
858     public List<ArtifactMetadata> getArtifactsByProjectVersionMetadata( String key, String value, String repositoryId )
859         throws MetadataRepositoryException
860     {
861         throw new UnsupportedOperationException( "not yet implemented in File backend" );
862     }
863
864     @Override
865     public List<ArtifactMetadata> getArtifactsByMetadata( String key, String value, String repositoryId )
866         throws MetadataRepositoryException
867     {
868         throw new UnsupportedOperationException( "not yet implemented in File backend" );
869     }
870
871     @Override
872     public List<ArtifactMetadata> getArtifactsByProperty( String key, String value, String repositoryId )
873         throws MetadataRepositoryException
874     {
875         throw new UnsupportedOperationException( "getArtifactsByProperty not yet implemented in File backend" );
876     }
877
878     private File getMetadataDirectory( String repoId, String facetId )
879         throws IOException
880     {
881         return new File( getBaseDirectory( repoId ), "facets/" + facetId );
882     }
883
884     private String join( Collection<String> ids )
885     {
886         if ( ids != null && !ids.isEmpty() )
887         {
888             StringBuilder s = new StringBuilder();
889             for ( String id : ids )
890             {
891                 s.append( id );
892                 s.append( "," );
893             }
894             return s.substring( 0, s.length() - 1 );
895         }
896         return "";
897     }
898
899     private void setProperty( Properties properties, String name, String value )
900     {
901         if ( value != null )
902         {
903             properties.setProperty( name, value );
904         }
905     }
906
907     @Override
908     public void updateArtifact( String repoId, String namespace, String projectId, String projectVersion,
909                                 ArtifactMetadata artifact )
910     {
911         try
912         {
913             ProjectVersionMetadata metadata = new ProjectVersionMetadata();
914             metadata.setId( projectVersion );
915             updateProjectVersion( repoId, namespace, projectId, metadata );
916
917             File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
918
919             Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
920
921             clearMetadataFacetProperties( artifact.getFacetList(), properties,
922                                           "artifact:facet:" + artifact.getId() + ":" );
923
924             String id = artifact.getId();
925             properties.setProperty( "artifact:updated:" + id,
926                                     Long.toString( artifact.getFileLastModified().getTime() ) );
927             properties.setProperty( "artifact:whenGathered:" + id,
928                                     Long.toString( artifact.getWhenGathered().getTime() ) );
929             properties.setProperty( "artifact:size:" + id, Long.toString( artifact.getSize() ) );
930             if ( artifact.getMd5() != null )
931             {
932                 properties.setProperty( "artifact:md5:" + id, artifact.getMd5() );
933             }
934             if ( artifact.getSha1() != null )
935             {
936                 properties.setProperty( "artifact:sha1:" + id, artifact.getSha1() );
937             }
938             properties.setProperty( "artifact:version:" + id, artifact.getVersion() );
939
940             Set<String> facetIds = new LinkedHashSet<String>( artifact.getFacetIds() );
941             String property = "artifact:facetIds:" + id;
942             facetIds.addAll( Arrays.asList( properties.getProperty( property, "" ).split( "," ) ) );
943             properties.setProperty( property, join( facetIds ) );
944
945             updateArtifactFacets( artifact, properties );
946
947             writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
948         }
949         catch ( IOException e )
950         {
951             // TODO
952             log.error( e.getMessage(), e );
953         }
954     }
955
956     private Properties readOrCreateProperties( File directory, String propertiesKey )
957     {
958         try
959         {
960             return readProperties( directory, propertiesKey );
961         }
962         catch ( FileNotFoundException | NoSuchFileException e )
963         {
964             // ignore and return new properties
965         }
966         catch ( IOException e )
967         {
968             // TODO
969             log.error( e.getMessage(), e );
970         }
971         return new Properties();
972     }
973
974     private Properties readProperties( File directory, String propertiesKey )
975         throws IOException
976     {
977         Properties properties = new Properties();
978         try (InputStream in = Files.newInputStream( new File( directory, propertiesKey + ".properties" ).toPath() ))
979         {
980
981             properties.load( in );
982         }
983         return properties;
984     }
985
986     @Override
987     public ProjectMetadata getProject( String repoId, String namespace, String projectId )
988         throws MetadataResolutionException
989     {
990         try
991         {
992             File directory = new File( getDirectory( repoId ), namespace + "/" + projectId );
993
994             Properties properties = readOrCreateProperties( directory, PROJECT_METADATA_KEY );
995
996             ProjectMetadata project = null;
997
998             String id = properties.getProperty( "id" );
999             if ( id != null )
1000             {
1001                 project = new ProjectMetadata();
1002                 project.setNamespace( properties.getProperty( "namespace" ) );
1003                 project.setId( id );
1004             }
1005
1006             return project;
1007         }
1008         catch ( IOException e )
1009         {
1010             throw new MetadataResolutionException( e.getMessage(), e );
1011         }
1012     }
1013
1014     @Override
1015     public ProjectVersionMetadata getProjectVersion( String repoId, String namespace, String projectId,
1016                                                      String projectVersion )
1017         throws MetadataResolutionException
1018     {
1019         try
1020         {
1021             File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1022
1023             Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1024             String id = properties.getProperty( "id" );
1025             ProjectVersionMetadata versionMetadata = null;
1026             if ( id != null )
1027             {
1028                 versionMetadata = new ProjectVersionMetadata();
1029                 versionMetadata.setId( id );
1030                 versionMetadata.setName( properties.getProperty( "name" ) );
1031                 versionMetadata.setDescription( properties.getProperty( "description" ) );
1032                 versionMetadata.setUrl( properties.getProperty( "url" ) );
1033                 versionMetadata.setIncomplete( Boolean.valueOf( properties.getProperty( "incomplete", "false" ) ) );
1034
1035                 String scmConnection = properties.getProperty( "scm.connection" );
1036                 String scmDeveloperConnection = properties.getProperty( "scm.developerConnection" );
1037                 String scmUrl = properties.getProperty( "scm.url" );
1038                 if ( scmConnection != null || scmDeveloperConnection != null || scmUrl != null )
1039                 {
1040                     Scm scm = new Scm();
1041                     scm.setConnection( scmConnection );
1042                     scm.setDeveloperConnection( scmDeveloperConnection );
1043                     scm.setUrl( scmUrl );
1044                     versionMetadata.setScm( scm );
1045                 }
1046
1047                 String ciSystem = properties.getProperty( "ci.system" );
1048                 String ciUrl = properties.getProperty( "ci.url" );
1049                 if ( ciSystem != null || ciUrl != null )
1050                 {
1051                     CiManagement ci = new CiManagement();
1052                     ci.setSystem( ciSystem );
1053                     ci.setUrl( ciUrl );
1054                     versionMetadata.setCiManagement( ci );
1055                 }
1056
1057                 String issueSystem = properties.getProperty( "issue.system" );
1058                 String issueUrl = properties.getProperty( "issue.url" );
1059                 if ( issueSystem != null || issueUrl != null )
1060                 {
1061                     IssueManagement issueManagement = new IssueManagement();
1062                     issueManagement.setSystem( issueSystem );
1063                     issueManagement.setUrl( issueUrl );
1064                     versionMetadata.setIssueManagement( issueManagement );
1065                 }
1066
1067                 String orgName = properties.getProperty( "org.name" );
1068                 String orgUrl = properties.getProperty( "org.url" );
1069                 if ( orgName != null || orgUrl != null )
1070                 {
1071                     Organization org = new Organization();
1072                     org.setName( orgName );
1073                     org.setUrl( orgUrl );
1074                     versionMetadata.setOrganization( org );
1075                 }
1076
1077                 boolean done = false;
1078                 int i = 0;
1079                 while ( !done )
1080                 {
1081                     String licenseName = properties.getProperty( "license." + i + ".name" );
1082                     String licenseUrl = properties.getProperty( "license." + i + ".url" );
1083                     if ( licenseName != null || licenseUrl != null )
1084                     {
1085                         License license = new License();
1086                         license.setName( licenseName );
1087                         license.setUrl( licenseUrl );
1088                         versionMetadata.addLicense( license );
1089                     }
1090                     else
1091                     {
1092                         done = true;
1093                     }
1094                     i++;
1095                 }
1096
1097                 done = false;
1098                 i = 0;
1099                 while ( !done )
1100                 {
1101                     String mailingListName = properties.getProperty( "mailingList." + i + ".name" );
1102                     if ( mailingListName != null )
1103                     {
1104                         MailingList mailingList = new MailingList();
1105                         mailingList.setName( mailingListName );
1106                         mailingList.setMainArchiveUrl( properties.getProperty( "mailingList." + i + ".archive" ) );
1107                         String p = properties.getProperty( "mailingList." + i + ".otherArchives" );
1108                         if ( p != null && p.length() > 0 )
1109                         {
1110                             mailingList.setOtherArchives( Arrays.asList( p.split( "," ) ) );
1111                         }
1112                         else
1113                         {
1114                             mailingList.setOtherArchives( Collections.<String>emptyList() );
1115                         }
1116                         mailingList.setPostAddress( properties.getProperty( "mailingList." + i + ".post" ) );
1117                         mailingList.setSubscribeAddress( properties.getProperty( "mailingList." + i + ".subscribe" ) );
1118                         mailingList.setUnsubscribeAddress(
1119                             properties.getProperty( "mailingList." + i + ".unsubscribe" ) );
1120                         versionMetadata.addMailingList( mailingList );
1121                     }
1122                     else
1123                     {
1124                         done = true;
1125                     }
1126                     i++;
1127                 }
1128
1129                 done = false;
1130                 i = 0;
1131                 while ( !done )
1132                 {
1133                     String dependencyArtifactId = properties.getProperty( "dependency." + i + ".artifactId" );
1134                     if ( dependencyArtifactId != null )
1135                     {
1136                         Dependency dependency = new Dependency();
1137                         dependency.setArtifactId( dependencyArtifactId );
1138                         dependency.setGroupId( properties.getProperty( "dependency." + i + ".groupId" ) );
1139                         dependency.setClassifier( properties.getProperty( "dependency." + i + ".classifier" ) );
1140                         dependency.setOptional(
1141                             Boolean.valueOf( properties.getProperty( "dependency." + i + ".optional" ) ) );
1142                         dependency.setScope( properties.getProperty( "dependency." + i + ".scope" ) );
1143                         dependency.setSystemPath( properties.getProperty( "dependency." + i + ".systemPath" ) );
1144                         dependency.setType( properties.getProperty( "dependency." + i + ".type" ) );
1145                         dependency.setVersion( properties.getProperty( "dependency." + i + ".version" ) );
1146                         dependency.setOptional(
1147                             Boolean.valueOf( properties.getProperty( "dependency." + i + ".optional" ) ) );
1148                         versionMetadata.addDependency( dependency );
1149                     }
1150                     else
1151                     {
1152                         done = true;
1153                     }
1154                     i++;
1155                 }
1156
1157                 String facetIds = properties.getProperty( "facetIds", "" );
1158                 if ( facetIds.length() > 0 )
1159                 {
1160                     for ( String facetId : facetIds.split( "," ) )
1161                     {
1162                         MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
1163                         if ( factory == null )
1164                         {
1165                             log.error( "Attempted to load unknown project version metadata facet: {}", facetId );
1166                         }
1167                         else
1168                         {
1169                             MetadataFacet facet = factory.createMetadataFacet();
1170                             Map<String, String> map = new HashMap<>();
1171                             for ( Object key : new ArrayList( properties.keySet() ) )
1172                             {
1173                                 String property = (String) key;
1174                                 if ( property.startsWith( facet.getFacetId() ) )
1175                                 {
1176                                     map.put( property.substring( facet.getFacetId().length() + 1 ),
1177                                              properties.getProperty( property ) );
1178                                 }
1179                             }
1180                             facet.fromProperties( map );
1181                             versionMetadata.addFacet( facet );
1182                         }
1183                     }
1184                 }
1185
1186                 updateProjectVersionFacets( versionMetadata, properties );
1187             }
1188             return versionMetadata;
1189         }
1190         catch ( IOException e )
1191         {
1192             throw new MetadataResolutionException( e.getMessage(), e );
1193         }
1194     }
1195
1196     @Override
1197     public Collection<String> getArtifactVersions( String repoId, String namespace, String projectId,
1198                                                    String projectVersion )
1199         throws MetadataResolutionException
1200     {
1201         try
1202         {
1203             File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1204
1205             Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1206
1207             Set<String> versions = new HashSet<String>();
1208             for ( Map.Entry entry : properties.entrySet() )
1209             {
1210                 String name = (String) entry.getKey();
1211                 if ( name.startsWith( "artifact:version:" ) )
1212                 {
1213                     versions.add( (String) entry.getValue() );
1214                 }
1215             }
1216             return versions;
1217         }
1218         catch ( IOException e )
1219         {
1220             throw new MetadataResolutionException( e.getMessage(), e );
1221         }
1222     }
1223
1224     @Override
1225     public Collection<ProjectVersionReference> getProjectReferences( String repoId, String namespace, String projectId,
1226                                                                      String projectVersion )
1227         throws MetadataResolutionException
1228     {
1229         try
1230         {
1231             File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1232
1233             Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1234             int numberOfRefs = Integer.parseInt( properties.getProperty( "ref:lastReferenceNum", "-1" ) ) + 1;
1235
1236             List<ProjectVersionReference> references = new ArrayList<>();
1237             for ( int i = 0; i < numberOfRefs; i++ )
1238             {
1239                 ProjectVersionReference reference = new ProjectVersionReference();
1240                 reference.setProjectId( properties.getProperty( "ref:reference." + i + ".projectId" ) );
1241                 reference.setNamespace( properties.getProperty( "ref:reference." + i + ".namespace" ) );
1242                 reference.setProjectVersion( properties.getProperty( "ref:reference." + i + ".projectVersion" ) );
1243                 reference.setReferenceType( ProjectVersionReference.ReferenceType.valueOf(
1244                     properties.getProperty( "ref:reference." + i + ".referenceType" ) ) );
1245                 references.add( reference );
1246             }
1247             return references;
1248         }
1249         catch ( IOException e )
1250         {
1251             throw new MetadataResolutionException( e.getMessage(), e );
1252         }
1253     }
1254
1255     @Override
1256     public Collection<String> getRootNamespaces( String repoId )
1257         throws MetadataResolutionException
1258     {
1259         return getNamespaces( repoId, null );
1260     }
1261
1262     @Override
1263     public Collection<String> getNamespaces( String repoId, String baseNamespace )
1264         throws MetadataResolutionException
1265     {
1266         try
1267         {
1268             List<String> allNamespaces = new ArrayList<>();
1269             File directory = getDirectory( repoId );
1270             File[] files = directory.listFiles();
1271             if ( files != null )
1272             {
1273                 for ( File namespace : files )
1274                 {
1275                     if ( new File( namespace, NAMESPACE_METADATA_KEY + ".properties" ).exists() )
1276                     {
1277                         allNamespaces.add( namespace.getName() );
1278                     }
1279                 }
1280             }
1281
1282             Set<String> namespaces = new LinkedHashSet<>();
1283             int fromIndex = baseNamespace != null ? baseNamespace.length() + 1 : 0;
1284             for ( String namespace : allNamespaces )
1285             {
1286                 if ( baseNamespace == null || namespace.startsWith( baseNamespace + "." ) )
1287                 {
1288                     int i = namespace.indexOf( '.', fromIndex );
1289                     if ( i >= 0 )
1290                     {
1291                         namespaces.add( namespace.substring( fromIndex, i ) );
1292                     }
1293                     else
1294                     {
1295                         namespaces.add( namespace.substring( fromIndex ) );
1296                     }
1297                 }
1298             }
1299             return new ArrayList<>( namespaces );
1300         }
1301         catch ( IOException e )
1302         {
1303             throw new MetadataResolutionException( e.getMessage(), e );
1304         }
1305     }
1306
1307     @Override
1308     public Collection<String> getProjects( String repoId, String namespace )
1309         throws MetadataResolutionException
1310     {
1311         try
1312         {
1313             List<String> projects = new ArrayList<>();
1314             File directory = new File( getDirectory( repoId ), namespace );
1315             File[] files = directory.listFiles();
1316             if ( files != null )
1317             {
1318                 for ( File project : files )
1319                 {
1320                     if ( new File( project, PROJECT_METADATA_KEY + ".properties" ).exists() )
1321                     {
1322                         projects.add( project.getName() );
1323                     }
1324                 }
1325             }
1326             return projects;
1327         }
1328         catch ( IOException e )
1329         {
1330             throw new MetadataResolutionException( e.getMessage(), e );
1331         }
1332     }
1333
1334     @Override
1335     public Collection<String> getProjectVersions( String repoId, String namespace, String projectId )
1336         throws MetadataResolutionException
1337     {
1338         try
1339         {
1340             List<String> projectVersions = new ArrayList<>();
1341             File directory = new File( getDirectory( repoId ), namespace + "/" + projectId );
1342             File[] files = directory.listFiles();
1343             if ( files != null )
1344             {
1345                 for ( File projectVersion : files )
1346                 {
1347                     if ( new File( projectVersion, PROJECT_VERSION_METADATA_KEY + ".properties" ).exists() )
1348                     {
1349                         projectVersions.add( projectVersion.getName() );
1350                     }
1351                 }
1352             }
1353             return projectVersions;
1354         }
1355         catch ( IOException e )
1356         {
1357             throw new MetadataResolutionException( e.getMessage(), e );
1358         }
1359     }
1360
1361     @Override
1362     public void removeProject( String repositoryId, String namespace, String projectId )
1363         throws MetadataRepositoryException
1364     {
1365         try
1366         {
1367             File directory = new File( getDirectory( repositoryId ), namespace + "/" + projectId );
1368             Files.deleteIfExists( directory.toPath() );
1369         }
1370         catch ( IOException e )
1371         {
1372             throw new MetadataRepositoryException( e.getMessage(), e );
1373         }
1374     }
1375
1376     @Override
1377     public void removeProjectVersion( String repoId, String namespace, String projectId, String projectVersion )
1378         throws MetadataRepositoryException
1379     {
1380         try
1381         {
1382             File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1383             Files.deleteIfExists( directory.toPath() );
1384         }
1385         catch ( IOException e )
1386         {
1387             throw new MetadataRepositoryException( e.getMessage(), e );
1388         }
1389
1390     }
1391
1392     private void writeProperties( Properties properties, File directory, String propertiesKey )
1393         throws IOException
1394     {
1395         directory.mkdirs();
1396         try (OutputStream os = Files.newOutputStream( new File( directory, propertiesKey + ".properties" ).toPath() ))
1397         {
1398             properties.store( os, null );
1399         }
1400     }
1401
1402     private static class ArtifactComparator
1403         implements Comparator<ArtifactMetadata>
1404     {
1405         @Override
1406         public int compare( ArtifactMetadata artifact1, ArtifactMetadata artifact2 )
1407         {
1408             if ( artifact1.getWhenGathered() == artifact2.getWhenGathered() )
1409             {
1410                 return 0;
1411             }
1412             if ( artifact1.getWhenGathered() == null )
1413             {
1414                 return 1;
1415             }
1416             if ( artifact2.getWhenGathered() == null )
1417             {
1418                 return -1;
1419             }
1420             return artifact1.getWhenGathered().compareTo( artifact2.getWhenGathered() );
1421         }
1422     }
1423
1424     @Override
1425     public List<ArtifactMetadata> getArtifacts( String repoId )
1426         throws MetadataRepositoryException
1427     {
1428         try
1429         {
1430             List<ArtifactMetadata> artifacts = new ArrayList<>();
1431             for ( String ns : getRootNamespaces( repoId ) )
1432             {
1433                 getArtifacts( artifacts, repoId, ns );
1434             }
1435             return artifacts;
1436         }
1437         catch ( MetadataResolutionException e )
1438         {
1439             throw new MetadataRepositoryException( e.getMessage(), e );
1440         }
1441     }
1442
1443     private void getArtifacts( List<ArtifactMetadata> artifacts, String repoId, String ns )
1444         throws MetadataResolutionException
1445     {
1446         for ( String namespace : getNamespaces( repoId, ns ) )
1447         {
1448             getArtifacts( artifacts, repoId, ns + "." + namespace );
1449         }
1450
1451         for ( String project : getProjects( repoId, ns ) )
1452         {
1453             for ( String version : getProjectVersions( repoId, ns, project ) )
1454             {
1455                 for ( ArtifactMetadata artifact : getArtifacts( repoId, ns, project, version ) )
1456                 {
1457                     artifacts.add( artifact );
1458                 }
1459             }
1460         }
1461     }
1462
1463     @Override
1464     public List<ArtifactMetadata> searchArtifacts( String text, String repositoryId, boolean exact )
1465         throws MetadataRepositoryException
1466     {
1467         throw new UnsupportedOperationException( "searchArtifacts not yet implemented in File backend" );
1468     }
1469
1470     @Override
1471     public List<ArtifactMetadata> searchArtifacts( String key, String text, String repositoryId, boolean exact )
1472         throws MetadataRepositoryException
1473     {
1474         throw new UnsupportedOperationException( "searchArtifacts not yet implemented in File backend" );
1475     }
1476 }