]> source.dussan.org Git - archiva.git/blob
110790af3e57e8268f35cd3950dd20ce70883b65
[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 java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileNotFoundException;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.LinkedHashSet;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Properties;
36 import java.util.Set;
37
38 import org.apache.archiva.metadata.model.ArtifactMetadata;
39 import org.apache.archiva.metadata.model.CiManagement;
40 import org.apache.archiva.metadata.model.Dependency;
41 import org.apache.archiva.metadata.model.IssueManagement;
42 import org.apache.archiva.metadata.model.License;
43 import org.apache.archiva.metadata.model.MailingList;
44 import org.apache.archiva.metadata.model.MetadataFacet;
45 import org.apache.archiva.metadata.model.MetadataFacetFactory;
46 import org.apache.archiva.metadata.model.Organization;
47 import org.apache.archiva.metadata.model.ProjectMetadata;
48 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
49 import org.apache.archiva.metadata.model.ProjectVersionReference;
50 import org.apache.archiva.metadata.model.Scm;
51 import org.apache.archiva.metadata.repository.MetadataRepository;
52 import org.apache.commons.io.FileUtils;
53 import org.apache.commons.io.IOUtils;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 /**
58  * @plexus.component role="org.apache.archiva.metadata.repository.MetadataRepository"
59  */
60 public class FileMetadataRepository
61     implements MetadataRepository
62 {
63     /**
64      * TODO: this isn't suitable for production use
65      *
66      * @plexus.configuration
67      */
68     private File directory = new File( System.getProperty( "user.home" ), ".archiva-metadata" );
69
70     /**
71      * @plexus.requirement role="org.apache.archiva.metadata.model.MetadataFacetFactory"
72      */
73     private Map<String, MetadataFacetFactory> metadataFacetFactories;
74
75     private static final Logger log = LoggerFactory.getLogger( FileMetadataRepository.class );
76
77     private static final String PROJECT_METADATA_KEY = "project-metadata";
78
79     private static final String PROJECT_VERSION_METADATA_KEY = "version-metadata";
80
81     private static final String NAMESPACE_METADATA_KEY = "namespace-metadata";
82
83     private static final String METADATA_KEY = "metadata";
84
85     public void updateProject( String repoId, ProjectMetadata project )
86     {
87         updateProject( repoId, project.getNamespace(), project.getId() );
88     }
89
90     private void updateProject( String repoId, String namespace, String id )
91     {
92         // TODO: this is a more braindead implementation than we would normally expect, for prototyping purposes
93         updateNamespace( repoId, namespace );
94
95         try
96         {
97             File namespaceDirectory = new File( this.directory, repoId + "/" + namespace );
98             Properties properties = new Properties();
99             properties.setProperty( "namespace", namespace );
100             properties.setProperty( "id", id );
101             writeProperties( properties, new File( namespaceDirectory, id ), PROJECT_METADATA_KEY );
102         }
103         catch ( IOException e )
104         {
105             // TODO!
106             e.printStackTrace();
107         }
108     }
109
110     public void updateProjectVersion( String repoId, String namespace, String projectId,
111                                       ProjectVersionMetadata versionMetadata )
112     {
113         updateProject( repoId, namespace, projectId );
114
115         File directory =
116             new File( this.directory, repoId + "/" + namespace + "/" + projectId + "/" + versionMetadata.getId() );
117
118         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
119         // remove properties that are not references or artifacts
120         for ( String name : properties.stringPropertyNames() )
121         {
122             if ( !name.contains( ":" ) && !name.equals( "facetIds" ) )
123             {
124                 properties.remove( name );
125             }
126         }
127         properties.setProperty( "id", versionMetadata.getId() );
128         setProperty( properties, "name", versionMetadata.getName() );
129         setProperty( properties, "description", versionMetadata.getDescription() );
130         setProperty( properties, "url", versionMetadata.getUrl() );
131         if ( versionMetadata.getScm() != null )
132         {
133             setProperty( properties, "scm.connection", versionMetadata.getScm().getConnection() );
134             setProperty( properties, "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection() );
135             setProperty( properties, "scm.url", versionMetadata.getScm().getUrl() );
136         }
137         if ( versionMetadata.getCiManagement() != null )
138         {
139             setProperty( properties, "ci.system", versionMetadata.getCiManagement().getSystem() );
140             setProperty( properties, "ci.url", versionMetadata.getCiManagement().getUrl() );
141         }
142         if ( versionMetadata.getIssueManagement() != null )
143         {
144             setProperty( properties, "issue.system", versionMetadata.getIssueManagement().getSystem() );
145             setProperty( properties, "issue.url", versionMetadata.getIssueManagement().getUrl() );
146         }
147         if ( versionMetadata.getOrganization() != null )
148         {
149             setProperty( properties, "org.name", versionMetadata.getOrganization().getName() );
150             setProperty( properties, "org.url", versionMetadata.getOrganization().getUrl() );
151         }
152         int i = 0;
153         for ( License license : versionMetadata.getLicenses() )
154         {
155             setProperty( properties, "license." + i + ".name", license.getName() );
156             setProperty( properties, "license." + i + ".url", license.getUrl() );
157             i++;
158         }
159         i = 0;
160         for ( MailingList mailingList : versionMetadata.getMailingLists() )
161         {
162             setProperty( properties, "mailingList." + i + ".archive", mailingList.getMainArchiveUrl() );
163             setProperty( properties, "mailingList." + i + ".name", mailingList.getName() );
164             setProperty( properties, "mailingList." + i + ".post", mailingList.getPostAddress() );
165             setProperty( properties, "mailingList." + i + ".unsubscribe", mailingList.getUnsubscribeAddress() );
166             setProperty( properties, "mailingList." + i + ".subscribe", mailingList.getSubscribeAddress() );
167             setProperty( properties, "mailingList." + i + ".otherArchives", join( mailingList.getOtherArchives() ) );
168             i++;
169         }
170         i = 0;
171         for ( Dependency dependency : versionMetadata.getDependencies() )
172         {
173             setProperty( properties, "dependency." + i + ".classifier", dependency.getClassifier() );
174             setProperty( properties, "dependency." + i + ".scope", dependency.getScope() );
175             setProperty( properties, "dependency." + i + ".systemPath", dependency.getSystemPath() );
176             setProperty( properties, "dependency." + i + ".artifactId", dependency.getArtifactId() );
177             setProperty( properties, "dependency." + i + ".groupId", dependency.getGroupId() );
178             setProperty( properties, "dependency." + i + ".version", dependency.getVersion() );
179             setProperty( properties, "dependency." + i + ".type", dependency.getType() );
180             i++;
181         }
182         Set<String> facetIds = new LinkedHashSet<String>( versionMetadata.getFacetIds() );
183         facetIds.addAll( Arrays.asList( properties.getProperty( "facetIds", "" ).split( "," ) ) );
184         properties.setProperty( "facetIds", join( facetIds ) );
185
186         for ( MetadataFacet facet : versionMetadata.getFacetList() )
187         {
188             properties.putAll( facet.toProperties() );
189         }
190
191         try
192         {
193             writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
194         }
195         catch ( IOException e )
196         {
197             // TODO
198             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
199         }
200     }
201
202     public void updateProjectReference( String repoId, String namespace, String projectId, String projectVersion,
203                                         ProjectVersionReference reference )
204     {
205         File directory = new File( this.directory, repoId + "/" + namespace + "/" + projectId + "/" + projectVersion );
206
207         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
208         int i = Integer.valueOf( properties.getProperty( "ref:lastReferenceNum", "-1" ) ) + 1;
209         setProperty( properties, "ref:lastReferenceNum", Integer.toString( i ) );
210         setProperty( properties, "ref:reference." + i + ".namespace", reference.getNamespace() );
211         setProperty( properties, "ref:reference." + i + ".projectId", reference.getProjectId() );
212         setProperty( properties, "ref:reference." + i + ".projectVersion", reference.getProjectVersion() );
213         setProperty( properties, "ref:reference." + i + ".referenceType", reference.getReferenceType().toString() );
214
215         try
216         {
217             writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
218         }
219         catch ( IOException e )
220         {
221             // TODO
222             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
223         }
224     }
225
226     public void updateNamespace( String repoId, String namespace )
227     {
228         try
229         {
230             File namespaceDirectory = new File( this.directory, repoId + "/" + namespace );
231             Properties properties = new Properties();
232             properties.setProperty( "namespace", namespace );
233             writeProperties( properties, namespaceDirectory, NAMESPACE_METADATA_KEY );
234
235         }
236         catch ( IOException e )
237         {
238             // TODO!
239             e.printStackTrace();
240         }
241     }
242
243     public List<String> getMetadataFacets( String repoId, String facetId )
244     {
245         File directory = getMetadataDirectory( repoId, facetId );
246         String[] list = directory.list();
247         return list != null ? Arrays.asList( list ) : Collections.<String>emptyList();
248     }
249
250     public MetadataFacet getMetadataFacet( String repositoryId, String facetId, String name )
251     {
252         Properties properties;
253         try
254         {
255             properties =
256                 readProperties( new File( getMetadataDirectory( repositoryId, facetId ), name ), METADATA_KEY );
257         }
258         catch ( FileNotFoundException e )
259         {
260             return null;
261         }
262         catch ( IOException e )
263         {
264             // TODO
265             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
266             return null;
267         }
268         MetadataFacet metadataFacet = null;
269         MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
270         if ( metadataFacetFactory != null )
271         {
272             metadataFacet = metadataFacetFactory.createMetadataFacet();
273             Map<String, String> map = new HashMap<String, String>();
274             for ( String key : properties.stringPropertyNames() )
275             {
276                 map.put( key, properties.getProperty( key ) );
277             }
278             metadataFacet.fromProperties( map );
279         }
280         return metadataFacet;
281     }
282
283     public void addMetadataFacet( String repositoryId, String facetId, String name, MetadataFacet metadataFacet )
284     {
285         Properties properties = new Properties();
286         properties.putAll( metadataFacet.toProperties() );
287
288         try
289         {
290             writeProperties( properties, new File( getMetadataDirectory( repositoryId, facetId ), name ),
291                              METADATA_KEY );
292         }
293         catch ( IOException e )
294         {
295             // TODO!
296             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
297         }
298     }
299
300     public void removeMetadataFacets( String repositoryId, String facetId )
301     {
302         try
303         {
304             FileUtils.deleteDirectory( getMetadataDirectory( repositoryId, facetId ) );
305         }
306         catch ( IOException e )
307         {
308             // TODO!
309             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
310         }
311     }
312
313     private File getMetadataDirectory( String repositoryId, String facetId )
314     {
315         return new File( this.directory, repositoryId + "/.meta/" + facetId );
316     }
317
318     private String join( Collection<String> ids )
319     {
320         if ( !ids.isEmpty() )
321         {
322             StringBuilder s = new StringBuilder();
323             for ( String id : ids )
324             {
325                 s.append( id );
326                 s.append( "," );
327             }
328             return s.substring( 0, s.length() - 1 );
329         }
330         return "";
331     }
332
333     private void setProperty( Properties properties, String name, String value )
334     {
335         if ( value != null )
336         {
337             properties.setProperty( name, value );
338         }
339     }
340
341     public void updateArtifact( String repoId, String namespace, String projectId, String projectVersion,
342                                 ArtifactMetadata artifact )
343     {
344         File directory = new File( this.directory, repoId + "/" + namespace + "/" + projectId + "/" + projectVersion );
345
346         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
347
348         properties.setProperty( "artifact:updated:" + artifact.getId(),
349                                 Long.toString( artifact.getFileLastModified().getTime() ) );
350         properties.setProperty( "artifact:whenGathered:" + artifact.getId(),
351                                 Long.toString( artifact.getWhenGathered().getTime() ) );
352         properties.setProperty( "artifact:size:" + artifact.getId(), Long.toString( artifact.getSize() ) );
353         properties.setProperty( "artifact:md5:" + artifact.getId(), artifact.getMd5() );
354         properties.setProperty( "artifact:sha1:" + artifact.getId(), artifact.getMd5() );
355         properties.setProperty( "artifact:version:" + artifact.getId(), artifact.getVersion() );
356
357         try
358         {
359             writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
360         }
361         catch ( IOException e )
362         {
363             // TODO
364             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
365         }
366     }
367
368     private Properties readOrCreateProperties( File directory, String propertiesKey )
369     {
370         try
371         {
372             return readProperties( directory, propertiesKey );
373         }
374         catch ( FileNotFoundException e )
375         {
376             // ignore and return new properties
377         }
378         catch ( IOException e )
379         {
380             // TODO
381             e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
382         }
383         return new Properties();
384     }
385
386     private Properties readProperties( File directory, String propertiesKey )
387         throws IOException
388     {
389         Properties properties = new Properties();
390         FileInputStream in = null;
391         try
392         {
393             in = new FileInputStream( new File( directory, propertiesKey + ".properties" ) );
394             properties.load( in );
395         }
396         finally
397         {
398             IOUtils.closeQuietly( in );
399         }
400         return properties;
401     }
402
403     public ProjectMetadata getProject( String repoId, String namespace, String projectId )
404     {
405         File directory = new File( this.directory, repoId + "/" + namespace + "/" + projectId );
406
407         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
408
409         ProjectMetadata project = new ProjectMetadata();
410         project.setNamespace( properties.getProperty( "namespace" ) );
411         project.setId( properties.getProperty( "id" ) );
412         return project;
413     }
414
415     public ProjectVersionMetadata getProjectVersion( String repoId, String namespace, String projectId,
416                                                      String projectVersion )
417     {
418         File directory = new File( this.directory, repoId + "/" + namespace + "/" + projectId + "/" + projectVersion );
419
420         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
421         String id = properties.getProperty( "id" );
422         ProjectVersionMetadata versionMetadata = null;
423         if ( id != null )
424         {
425             versionMetadata = new ProjectVersionMetadata();
426             versionMetadata.setId( id );
427             versionMetadata.setName( properties.getProperty( "name" ) );
428             versionMetadata.setDescription( properties.getProperty( "description" ) );
429             versionMetadata.setUrl( properties.getProperty( "url" ) );
430
431             String scmConnection = properties.getProperty( "scm.connection" );
432             String scmDeveloperConnection = properties.getProperty( "scm.developerConnection" );
433             String scmUrl = properties.getProperty( "scm.url" );
434             if ( scmConnection != null || scmDeveloperConnection != null || scmUrl != null )
435             {
436                 Scm scm = new Scm();
437                 scm.setConnection( scmConnection );
438                 scm.setDeveloperConnection( scmDeveloperConnection );
439                 scm.setUrl( scmUrl );
440                 versionMetadata.setScm( scm );
441             }
442
443             String ciSystem = properties.getProperty( "ci.system" );
444             String ciUrl = properties.getProperty( "ci.url" );
445             if ( ciSystem != null || ciUrl != null )
446             {
447                 CiManagement ci = new CiManagement();
448                 ci.setSystem( ciSystem );
449                 ci.setUrl( ciUrl );
450                 versionMetadata.setCiManagement( ci );
451             }
452
453             String issueSystem = properties.getProperty( "issue.system" );
454             String issueUrl = properties.getProperty( "issue.url" );
455             if ( issueSystem != null || issueUrl != null )
456             {
457                 IssueManagement issueManagement = new IssueManagement();
458                 issueManagement.setSystem( issueSystem );
459                 issueManagement.setUrl( issueUrl );
460                 versionMetadata.setIssueManagement( issueManagement );
461             }
462
463             String orgName = properties.getProperty( "org.name" );
464             String orgUrl = properties.getProperty( "org.url" );
465             if ( orgName != null || orgUrl != null )
466             {
467                 Organization org = new Organization();
468                 org.setName( orgName );
469                 org.setUrl( orgUrl );
470                 versionMetadata.setOrganization( org );
471             }
472
473             boolean done = false;
474             int i = 0;
475             while ( !done )
476             {
477                 String licenseName = properties.getProperty( "license." + i + ".name" );
478                 String licenseUrl = properties.getProperty( "license." + i + ".url" );
479                 if ( licenseName != null || licenseUrl != null )
480                 {
481                     License license = new License();
482                     license.setName( licenseName );
483                     license.setUrl( licenseUrl );
484                     versionMetadata.addLicense( license );
485                 }
486                 else
487                 {
488                     done = true;
489                 }
490                 i++;
491             }
492
493             done = false;
494             i = 0;
495             while ( !done )
496             {
497                 String mailingListName = properties.getProperty( "mailingList." + i + ".name" );
498                 if ( mailingListName != null )
499                 {
500                     MailingList mailingList = new MailingList();
501                     mailingList.setName( mailingListName );
502                     mailingList.setMainArchiveUrl( properties.getProperty( "mailingList." + i + ".archive" ) );
503                     mailingList.setOtherArchives(
504                         Arrays.asList( properties.getProperty( "mailingList." + i + ".otherArchives" ).split( "," ) ) );
505                     mailingList.setPostAddress( properties.getProperty( "mailingList." + i + ".post" ) );
506                     mailingList.setSubscribeAddress( properties.getProperty( "mailingList." + i + ".subscribe" ) );
507                     mailingList.setUnsubscribeAddress( properties.getProperty( "mailingList." + i + ".unsubscribe" ) );
508                     versionMetadata.addMailingList( mailingList );
509                 }
510                 else
511                 {
512                     done = true;
513                 }
514                 i++;
515             }
516
517             done = false;
518             i = 0;
519             while ( !done )
520             {
521                 String dependencyArtifactId = properties.getProperty( "dependency." + i + ".artifactId" );
522                 if ( dependencyArtifactId != null )
523                 {
524                     Dependency dependency = new Dependency();
525                     dependency.setArtifactId( dependencyArtifactId );
526                     dependency.setGroupId( properties.getProperty( "dependency." + i + ".groupId" ) );
527                     dependency.setClassifier( properties.getProperty( "dependency." + i + ".classifier" ) );
528                     dependency.setOptional(
529                         Boolean.valueOf( properties.getProperty( "dependency." + i + ".optional" ) ) );
530                     dependency.setScope( properties.getProperty( "dependency." + i + ".scope" ) );
531                     dependency.setSystemPath( properties.getProperty( "dependency." + i + ".systemPath" ) );
532                     dependency.setType( properties.getProperty( "dependency." + i + ".type" ) );
533                     dependency.setVersion( properties.getProperty( "dependency." + i + ".version" ) );
534                     versionMetadata.addDependency( dependency );
535                 }
536                 else
537                 {
538                     done = true;
539                 }
540                 i++;
541             }
542
543             for ( String facetId : properties.getProperty( "facetIds" ).split( "," ) )
544             {
545                 MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
546                 if ( factory == null )
547                 {
548                     log.error( "Attempted to load unknown metadata facet: " + facetId );
549                 }
550                 else
551                 {
552                     MetadataFacet facet = factory.createMetadataFacet();
553                     Map<String, String> map = new HashMap<String, String>();
554                     for ( String key : properties.stringPropertyNames() )
555                     {
556                         if ( key.startsWith( facet.getFacetId() ) )
557                         {
558                             map.put( key, properties.getProperty( key ) );
559                         }
560                     }
561                     facet.fromProperties( map );
562                     versionMetadata.addFacet( facet );
563                 }
564             }
565
566             for ( MetadataFacet facet : versionMetadata.getFacetList() )
567             {
568                 properties.putAll( facet.toProperties() );
569             }
570         }
571         return versionMetadata;
572     }
573
574     public Collection<String> getArtifactVersions( String repoId, String namespace, String projectId,
575                                                    String projectVersion )
576     {
577         File directory = new File( this.directory, repoId + "/" + namespace + "/" + projectId + "/" + projectVersion );
578
579         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
580
581         List<String> versions = new ArrayList<String>();
582         for ( Map.Entry entry : properties.entrySet() )
583         {
584             String name = (String) entry.getKey();
585             if ( name.startsWith( "version:" ) )
586             {
587                 versions.add( (String) entry.getValue() );
588             }
589         }
590         return versions;
591     }
592
593     public Collection<ProjectVersionReference> getProjectReferences( String repoId, String namespace, String projectId,
594                                                                      String projectVersion )
595     {
596         File directory = new File( this.directory, repoId + "/" + namespace + "/" + projectId + "/" + projectVersion );
597
598         Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
599         int numberOfRefs = Integer.valueOf( properties.getProperty( "ref:lastReferenceNum", "-1" ) ) + 1;
600
601         List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
602         for ( int i = 0; i < numberOfRefs; i++ )
603         {
604             ProjectVersionReference reference = new ProjectVersionReference();
605             reference.setProjectId( properties.getProperty( "ref:reference." + i + ".projectId" ) );
606             reference.setNamespace( properties.getProperty( "ref:reference." + i + ".namespace" ) );
607             reference.setProjectVersion( properties.getProperty( "ref:reference." + i + ".projectVersion" ) );
608             reference.setReferenceType( ProjectVersionReference.ReferenceType.valueOf(
609                 properties.getProperty( "ref:reference." + i + ".referenceType" ) ) );
610             references.add( reference );
611         }
612         return references;
613     }
614
615     public Collection<String> getRootNamespaces( String repoId )
616     {
617         return getNamespaces( repoId, null );
618     }
619
620     public Collection<String> getNamespaces( String repoId, String baseNamespace )
621     {
622         List<String> allNamespaces = new ArrayList<String>();
623         File directory = new File( this.directory, repoId );
624         File[] files = directory.listFiles();
625         if ( files != null )
626         {
627             for ( File namespace : files )
628             {
629                 if ( new File( namespace, NAMESPACE_METADATA_KEY + ".properties" ).exists() )
630                 {
631                     allNamespaces.add( namespace.getName() );
632                 }
633             }
634         }
635
636         Set<String> namespaces = new LinkedHashSet<String>();
637         int fromIndex = baseNamespace != null ? baseNamespace.length() + 1 : 0;
638         for ( String namespace : allNamespaces )
639         {
640             if ( baseNamespace == null || namespace.startsWith( baseNamespace + "." ) )
641             {
642                 int i = namespace.indexOf( '.', fromIndex );
643                 if ( i >= 0 )
644                 {
645                     namespaces.add( namespace.substring( fromIndex, i ) );
646                 }
647                 else
648                 {
649                     namespaces.add( namespace.substring( fromIndex ) );
650                 }
651             }
652         }
653         return new ArrayList<String>( namespaces );
654     }
655
656     public Collection<String> getProjects( String repoId, String namespace )
657     {
658         List<String> projects = new ArrayList<String>();
659         File directory = new File( this.directory, repoId + "/" + namespace );
660         File[] files = directory.listFiles();
661         if ( files != null )
662         {
663             for ( File project : files )
664             {
665                 if ( new File( project, PROJECT_METADATA_KEY + ".properties" ).exists() )
666                 {
667                     projects.add( project.getName() );
668                 }
669             }
670         }
671         return projects;
672     }
673
674     public Collection<String> getProjectVersions( String repoId, String namespace, String projectId )
675     {
676         List<String> projectVersions = new ArrayList<String>();
677         File directory = new File( this.directory, repoId + "/" + namespace + "/" + projectId );
678         File[] files = directory.listFiles();
679         if ( files != null )
680         {
681             for ( File projectVersion : files )
682             {
683                 if ( new File( projectVersion, PROJECT_VERSION_METADATA_KEY + ".properties" ).exists() )
684                 {
685                     projectVersions.add( projectVersion.getName() );
686                 }
687             }
688         }
689         return projectVersions;
690     }
691
692     private void writeProperties( Properties properties, File directory, String propertiesKey )
693         throws IOException
694     {
695         directory.mkdirs();
696         FileOutputStream os = new FileOutputStream( new File( directory, propertiesKey + ".properties" ) );
697         try
698         {
699             properties.store( os, null );
700         }
701         finally
702         {
703             IOUtils.closeQuietly( os );
704         }
705     }
706
707     public void setDirectory( File directory )
708     {
709         this.directory = directory;
710     }
711
712     public void setMetadataFacetFactories( Map<String, MetadataFacetFactory> metadataFacetFactories )
713     {
714         this.metadataFacetFactories = metadataFacetFactories;
715     }
716 }